一对零或一关系,其中 FK 是从属表上的复合 PK 的一部分
One-to-Zero-or-One relationship where the FK is part of a compoun PK on dependent tables
我正在用 Entity Framework 6.1.2 为这两个 table 开发一个库:
CREATE TABLE [dbo].[CODES]
(
[CODE] [nvarchar](20) NOT NULL,
[ ... ],
CONSTRAINT [PK_CODES] PRIMARY KEY CLUSTERED
(
[CODE] ASC
)
)
CREATE TABLE [dbo].[AGGREGATIONS]
(
[ID_AGGREGATION] INT IDENTITY(1,1) NOT NULL,
[CODE_LEVEL] TINYINT NOT NULL,
[CODE] NVARCHAR(20) NOT NULL,
[ ... ],
CONSTRAINT [PK_AGGREGATIONS] PRIMARY KEY CLUSTERED
(
[ID_AGGREGATION] ASC
),
CONSTRAINT [FK_AGGREGATIONS_CODES] FOREIGN KEY ([CODE]) REFERENCES [dbo].[CODES] ([CODE])
)
关系:
我 CODES
可以有零个或一个 AGGREGATIONS
,但是 AGGREGATIONS
会有一个 CODES
。
为此,我有这两个实体 类:
public class CODES
{
public string CODE { get; set; }
[ ... ]
public virtual AGGREGATIONS Aggregation { get; set; }
public virtual AGGREGATION_CHILDS AggregationChild { get; set; }
}
public class AGGREGATIONS
{
public int ID_AGGREGATION { get; set; }
public string CODE { get; set; }
public byte CODE_LEVEL { get; set; }
public virtual CODES Code { get; set; }
}
我试过在聚合的 EntityTypeConfiguration<AGGREGATIONS>
:
上设置 AGGREGATIONS
和 CODES
之间的关系
HasKey(ag => ag.ID_AGGREGATION);
HasRequired(ag => ag.Code).WithOptional(c => c.Aggregation);
但是我不知道如何将AGGREGATIONS.CODE
设置为这个关系中的外键。
如何设置这段关系的FK?
更新
我需要使用 AGGREGATIONS.ID_AGGREGATION
因为还有另一个 table 有一个到 AGGREGATIONS
和 CODES
的外键 tables:
CREATE TABLE [dbo].[AGGREGATION_CHILDS]
(
[ID_AGGREGATION] [int] NOT NULL,
[CODE] [nvarchar](20) NOT NULL,
[CODE_LEVEL] [tinyint] NOT NULL,
[POSITION] [int] NOT NULL,
CONSTRAINT [PK_AGGREGATION_CHILDS] PRIMARY KEY CLUSTERED
(
[ID_AGGREGATION] ASC,
[CODE] ASC
),
CONSTRAINT [FK_AGGREGATION_CHILDS_AGGREGATIONS] FOREIGN KEY ([ID_AGGREGATION]) REFERENCES [AGGREGATIONS]([ID_AGGREGATION]),
CONSTRAINT [FK_AGGREGATION_CHILDS_CODES] FOREIGN KEY ([CODE]) REFERENCES [CODES]([CODE])
如果我按照您在 中的建议进行操作,我将在 AGGREGATION_CHILDS
table 中有两列 CODE
。其中之一将是 AGGREGATIONS
table 和 CODES
table 的外键。而另一个FK到CODES
table.
我想你快到了。对于可选的 Codes.Aggregation
尝试:
HasRequired(ag => ag.Code).WithOptional(c => c.Aggregation);
或在您的上下文中 class:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Aggregations>()
.HasRequired(a => a.Code)
.WithOptional(c => c.Aggregation);
}
在一对一关系中,EF 要求依赖实体的键也必须是主体的外键,因此,您的模型将是这样的:
public class CODES
{
[Key]
public string CODE { get; set; }
[ ... ]
public virtual AGGREGATIONS Aggregation { get; set; }
}
public class AGGREGATIONS
{
[Key, ForeignKey("Codes")]
public string CODE { get; set; }
public byte CODE_LEVEL { get; set; }
public virtual CODES Code { get; set; }
}
如果您需要使用 Fluent Api,我想您可以在 Aggregations
的配置 class 中执行此操作:
HasKey(ag=>ag.Code);
HasRequired(ag => ag.Code).WithOptional(c => c.Aggregation);
您可以在此 page 中找到更多信息。
更新 1
为了实现你想要的,由于我在上面评论的限制,你不能在依赖实体中声明 FK 属性。所以你的模型会是这样的:
public class CODES
{
[Key]
public string CODE { get; set; }
[Required]
public virtual AGGREGATIONS Aggregation { get; set; }
public ICollection<AGGREGATION_CHILDS> AggregationChilds { get; set; }
}
public class AGGREGATIONS
{
[Key]
public int ID_AGGREGATION { get; set; }
public byte CODE_LEVEL { get; set; }
public virtual CODES Code { get; set; }
public ICollection<AGGREGATION_CHILDS> AggregationChilds { get; set; }
}
public class AGGREGATION_CHILDS
{
[Key,Column(Order = 0),ForeignKey("Code")]
public string CODE { get; set; }
[Key,Column(Order = 1),ForeignKey("Aggregation")]
public int ID_AGGREGATION { get; set; }
public virtual CODES Code { get; set; }
public virtual AGGREGATIONS Aggregation { get; set; }
}
如果您不想使用数据注释,您可以删除所有属性并在配置中使用 Fluent Api 指定相同的属性 classes:
public class CodesMap : EntityTypeConfiguration<CODES>
{
public CodesMap()
{
// Primary Key
this.HasKey(t => t.CODE);
}
}
public class AggregationsMap : EntityTypeConfiguration<AGGREGATIONS>
{
public AggregationsMap()
{
// Primary Key
this.HasKey(t => t.ID_AGGREGATION);
HasRequired(ag => ag.Code).WithOptional(c => c.Aggregation);
}
}
public class AggregationChildsMap : EntityTypeConfiguration<AGGREGATIONS_CHILDS>
{
public AggregationChildsMap()
{
// Primary Key
this.HasKey(t => new{t.CODE,t.ID_AGGREGATION});
HasRequired(t => t.Code).WitMany(c => c.AggregationChilds).HasForeignKey(t=>t.CODE);
HasRequired(t => t.Aggregation).WitMany(ag => ag.AggregationChilds).HasForeignKey(t=>t.ID_AGGREGATION);
}
}
更新 2
无法在 AGGREGATION_CHILDS
中指定复合 PK 并配置此实体与 AGGREGATIONS
之间的一对一关系,除非复合键是 [=16= 中的键] 也。如果要创建一对一关系并在依赖实体中指定 FK 属性,则该 FK 也必须是 PK,因此两个实体必须共享相同的 PK。如果您在该依赖实体中声明另一个键,FK 与另一个关系相关,EF 会期望这两个关系应该是一对多的(如我在更新 1 中显示的示例)。如果您尝试创建两个一对一关系,并尝试将依赖端的 PK 与主体的 PK 进行复合,那么您将收到此异常:
AGGREGATION_CHILDS_Aggregation_Source: : Multiplicity is not valid in
Role 'AGGREGATION_CHILDS_Aggregation_Source' in relationship
'AGGREGATION_CHILDS_Aggregation'. Because the Dependent Role
properties are not the key properties, the upper bound of the
multiplicity of the Dependent Role must be '*'.
AGGREGATION_CHILDS_Code_Source: : Multiplicity is not valid in Role
'AGGREGATION_CHILDS_Code_Source' in relationship
'AGGREGATION_CHILDS_Code'. Because the Dependent Role properties are
not the key properties, the upper bound of the multiplicity of the
Dependent Role must be '*'.
我是这样解决问题的:
public class CODES
{
public string CODE { get; set; }
public byte CODE_LEVEL { get; set; }
[ ... ]
public virtual AGGREGATION_CHILDS AggregationChild { get; set; }
public virtual AGGREGATIONS Aggregation { get; set; }
}
public class AGGREGATIONS
{
public string CODE { get; set; }
public string CREATED { get; set; }
public virtual ICollection<AGGREGATION_CHILDS> AggregationChilds { get; set; }
public virtual CODES Code { get; set; }
}
public class AGGREGATION_CHILDS
{
public string CODE { get; set; }
public string PARENT_CODE { get; set; }
public int POSITION { get; set; }
public AGGREGATIONS Aggregation { get; set; }
public CODES Code { get; set; }
}
以及他们的地图:
class AGGREGATIONSConfiguration : EntityTypeConfiguration<AGGREGATIONS>
{
public AGGREGATIONSConfiguration()
{
HasKey(ag => ag.CODE);
Property(ag => ag.CODE)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
Property(ag => ag.CODE)
.HasMaxLength(20)
.IsRequired();
Property(ag => ag.CREATED)
.HasMaxLength(50)
.IsOptional();
HasRequired(ag => ag.Code)
.WithOptional(c => c.Aggregation)
.WillCascadeOnDelete(false);
}
}
class AGGREGATION_CHILDSConfiguration : EntityTypeConfiguration<AGGREGATION_CHILDS>
{
public AGGREGATION_CHILDSConfiguration()
{
HasKey(ag_ch => ag_ch.CODE);
Property(ag_ch => ag_ch.CODE)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
Property(ag_ch => ag_ch.CODE)
.HasMaxLength(20)
.IsRequired();
Property(ag_ch => ag_ch.PARENT_CODE)
.HasMaxLength(20)
.IsRequired();
HasRequired(ag_ch => ag_ch.Aggregation)
.WithMany(ag => ag.AggregationChilds)
.HasForeignKey(ag_ch => ag_ch.PARENT_CODE);
HasRequired(ag_ch => ag_ch.Code)
.WithOptional(c => c.AggregationChild)
.WillCascadeOnDelete(false);
}
}
CODESConfiguration
与此处无关。
我在 AGGREGATIONS
和 AGGREGATION_CHILDS
上将 CODE
用作 PK,还用作 FK 到 CODES
table。
我已从 AGGREGATIONS
table 中删除 ID_AGGREGATION
并在 AGGREGATION_CHILDS
table.
上删除复合 PK
我希望它能帮助那些对一对零或一关系有同样问题的人。
我正在用 Entity Framework 6.1.2 为这两个 table 开发一个库:
CREATE TABLE [dbo].[CODES]
(
[CODE] [nvarchar](20) NOT NULL,
[ ... ],
CONSTRAINT [PK_CODES] PRIMARY KEY CLUSTERED
(
[CODE] ASC
)
)
CREATE TABLE [dbo].[AGGREGATIONS]
(
[ID_AGGREGATION] INT IDENTITY(1,1) NOT NULL,
[CODE_LEVEL] TINYINT NOT NULL,
[CODE] NVARCHAR(20) NOT NULL,
[ ... ],
CONSTRAINT [PK_AGGREGATIONS] PRIMARY KEY CLUSTERED
(
[ID_AGGREGATION] ASC
),
CONSTRAINT [FK_AGGREGATIONS_CODES] FOREIGN KEY ([CODE]) REFERENCES [dbo].[CODES] ([CODE])
)
关系:
我 CODES
可以有零个或一个 AGGREGATIONS
,但是 AGGREGATIONS
会有一个 CODES
。
为此,我有这两个实体 类:
public class CODES
{
public string CODE { get; set; }
[ ... ]
public virtual AGGREGATIONS Aggregation { get; set; }
public virtual AGGREGATION_CHILDS AggregationChild { get; set; }
}
public class AGGREGATIONS
{
public int ID_AGGREGATION { get; set; }
public string CODE { get; set; }
public byte CODE_LEVEL { get; set; }
public virtual CODES Code { get; set; }
}
我试过在聚合的 EntityTypeConfiguration<AGGREGATIONS>
:
AGGREGATIONS
和 CODES
之间的关系
HasKey(ag => ag.ID_AGGREGATION);
HasRequired(ag => ag.Code).WithOptional(c => c.Aggregation);
但是我不知道如何将AGGREGATIONS.CODE
设置为这个关系中的外键。
如何设置这段关系的FK?
更新
我需要使用 AGGREGATIONS.ID_AGGREGATION
因为还有另一个 table 有一个到 AGGREGATIONS
和 CODES
的外键 tables:
CREATE TABLE [dbo].[AGGREGATION_CHILDS]
(
[ID_AGGREGATION] [int] NOT NULL,
[CODE] [nvarchar](20) NOT NULL,
[CODE_LEVEL] [tinyint] NOT NULL,
[POSITION] [int] NOT NULL,
CONSTRAINT [PK_AGGREGATION_CHILDS] PRIMARY KEY CLUSTERED
(
[ID_AGGREGATION] ASC,
[CODE] ASC
),
CONSTRAINT [FK_AGGREGATION_CHILDS_AGGREGATIONS] FOREIGN KEY ([ID_AGGREGATION]) REFERENCES [AGGREGATIONS]([ID_AGGREGATION]),
CONSTRAINT [FK_AGGREGATION_CHILDS_CODES] FOREIGN KEY ([CODE]) REFERENCES [CODES]([CODE])
如果我按照您在 AGGREGATION_CHILDS
table 中有两列 CODE
。其中之一将是 AGGREGATIONS
table 和 CODES
table 的外键。而另一个FK到CODES
table.
我想你快到了。对于可选的 Codes.Aggregation
尝试:
HasRequired(ag => ag.Code).WithOptional(c => c.Aggregation);
或在您的上下文中 class:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Aggregations>()
.HasRequired(a => a.Code)
.WithOptional(c => c.Aggregation);
}
在一对一关系中,EF 要求依赖实体的键也必须是主体的外键,因此,您的模型将是这样的:
public class CODES
{
[Key]
public string CODE { get; set; }
[ ... ]
public virtual AGGREGATIONS Aggregation { get; set; }
}
public class AGGREGATIONS
{
[Key, ForeignKey("Codes")]
public string CODE { get; set; }
public byte CODE_LEVEL { get; set; }
public virtual CODES Code { get; set; }
}
如果您需要使用 Fluent Api,我想您可以在 Aggregations
的配置 class 中执行此操作:
HasKey(ag=>ag.Code);
HasRequired(ag => ag.Code).WithOptional(c => c.Aggregation);
您可以在此 page 中找到更多信息。
更新 1
为了实现你想要的,由于我在上面评论的限制,你不能在依赖实体中声明 FK 属性。所以你的模型会是这样的:
public class CODES
{
[Key]
public string CODE { get; set; }
[Required]
public virtual AGGREGATIONS Aggregation { get; set; }
public ICollection<AGGREGATION_CHILDS> AggregationChilds { get; set; }
}
public class AGGREGATIONS
{
[Key]
public int ID_AGGREGATION { get; set; }
public byte CODE_LEVEL { get; set; }
public virtual CODES Code { get; set; }
public ICollection<AGGREGATION_CHILDS> AggregationChilds { get; set; }
}
public class AGGREGATION_CHILDS
{
[Key,Column(Order = 0),ForeignKey("Code")]
public string CODE { get; set; }
[Key,Column(Order = 1),ForeignKey("Aggregation")]
public int ID_AGGREGATION { get; set; }
public virtual CODES Code { get; set; }
public virtual AGGREGATIONS Aggregation { get; set; }
}
如果您不想使用数据注释,您可以删除所有属性并在配置中使用 Fluent Api 指定相同的属性 classes:
public class CodesMap : EntityTypeConfiguration<CODES>
{
public CodesMap()
{
// Primary Key
this.HasKey(t => t.CODE);
}
}
public class AggregationsMap : EntityTypeConfiguration<AGGREGATIONS>
{
public AggregationsMap()
{
// Primary Key
this.HasKey(t => t.ID_AGGREGATION);
HasRequired(ag => ag.Code).WithOptional(c => c.Aggregation);
}
}
public class AggregationChildsMap : EntityTypeConfiguration<AGGREGATIONS_CHILDS>
{
public AggregationChildsMap()
{
// Primary Key
this.HasKey(t => new{t.CODE,t.ID_AGGREGATION});
HasRequired(t => t.Code).WitMany(c => c.AggregationChilds).HasForeignKey(t=>t.CODE);
HasRequired(t => t.Aggregation).WitMany(ag => ag.AggregationChilds).HasForeignKey(t=>t.ID_AGGREGATION);
}
}
更新 2
无法在 AGGREGATION_CHILDS
中指定复合 PK 并配置此实体与 AGGREGATIONS
之间的一对一关系,除非复合键是 [=16= 中的键] 也。如果要创建一对一关系并在依赖实体中指定 FK 属性,则该 FK 也必须是 PK,因此两个实体必须共享相同的 PK。如果您在该依赖实体中声明另一个键,FK 与另一个关系相关,EF 会期望这两个关系应该是一对多的(如我在更新 1 中显示的示例)。如果您尝试创建两个一对一关系,并尝试将依赖端的 PK 与主体的 PK 进行复合,那么您将收到此异常:
AGGREGATION_CHILDS_Aggregation_Source: : Multiplicity is not valid in Role 'AGGREGATION_CHILDS_Aggregation_Source' in relationship 'AGGREGATION_CHILDS_Aggregation'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.
AGGREGATION_CHILDS_Code_Source: : Multiplicity is not valid in Role 'AGGREGATION_CHILDS_Code_Source' in relationship 'AGGREGATION_CHILDS_Code'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.
我是这样解决问题的:
public class CODES
{
public string CODE { get; set; }
public byte CODE_LEVEL { get; set; }
[ ... ]
public virtual AGGREGATION_CHILDS AggregationChild { get; set; }
public virtual AGGREGATIONS Aggregation { get; set; }
}
public class AGGREGATIONS
{
public string CODE { get; set; }
public string CREATED { get; set; }
public virtual ICollection<AGGREGATION_CHILDS> AggregationChilds { get; set; }
public virtual CODES Code { get; set; }
}
public class AGGREGATION_CHILDS
{
public string CODE { get; set; }
public string PARENT_CODE { get; set; }
public int POSITION { get; set; }
public AGGREGATIONS Aggregation { get; set; }
public CODES Code { get; set; }
}
以及他们的地图:
class AGGREGATIONSConfiguration : EntityTypeConfiguration<AGGREGATIONS>
{
public AGGREGATIONSConfiguration()
{
HasKey(ag => ag.CODE);
Property(ag => ag.CODE)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
Property(ag => ag.CODE)
.HasMaxLength(20)
.IsRequired();
Property(ag => ag.CREATED)
.HasMaxLength(50)
.IsOptional();
HasRequired(ag => ag.Code)
.WithOptional(c => c.Aggregation)
.WillCascadeOnDelete(false);
}
}
class AGGREGATION_CHILDSConfiguration : EntityTypeConfiguration<AGGREGATION_CHILDS>
{
public AGGREGATION_CHILDSConfiguration()
{
HasKey(ag_ch => ag_ch.CODE);
Property(ag_ch => ag_ch.CODE)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
Property(ag_ch => ag_ch.CODE)
.HasMaxLength(20)
.IsRequired();
Property(ag_ch => ag_ch.PARENT_CODE)
.HasMaxLength(20)
.IsRequired();
HasRequired(ag_ch => ag_ch.Aggregation)
.WithMany(ag => ag.AggregationChilds)
.HasForeignKey(ag_ch => ag_ch.PARENT_CODE);
HasRequired(ag_ch => ag_ch.Code)
.WithOptional(c => c.AggregationChild)
.WillCascadeOnDelete(false);
}
}
CODESConfiguration
与此处无关。
我在 AGGREGATIONS
和 AGGREGATION_CHILDS
上将 CODE
用作 PK,还用作 FK 到 CODES
table。
我已从 AGGREGATIONS
table 中删除 ID_AGGREGATION
并在 AGGREGATION_CHILDS
table.
我希望它能帮助那些对一对零或一关系有同样问题的人。