[英]One-to-Zero-or-One relationship where the FK is part of a compoun PK on dependent tables
I'm developing a library with Entity Framework 6.1.2 for these two tables: 我正在为这两个表开发一个包含Entity Framework 6.1.2的库:
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])
)
Relationship: 关系:
I CODES
could have zero or one AGGREGATIONS
, but an AGGREGATIONS
will have one CODES
. 我的CODES
可能有零个或一个AGGREGATIONS
,但是AGGREGATIONS
会有一个CODES
。
To do it, I have these two entity classes: 为此,我有这两个实体类:
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; }
}
I have tried this to set relationship between AGGREGATIONS
and CODES
on Aggregations' EntityTypeConfiguration<AGGREGATIONS>
: 我试过这个在Aggregations的EntityTypeConfiguration<AGGREGATIONS>
上设置AGGREGATIONS
和CODES
之间的关系:
HasKey(ag => ag.ID_AGGREGATION);
HasRequired(ag => ag.Code).WithOptional(c => c.Aggregation);
But I don't know how to set AGGREGATIONS.CODE
as foreign key in this relantionship. 但我不知道如何在这种关系中将AGGREGATIONS.CODE
设置为外键。
How can I set FK on this relationship? 如何在这种关系上设置FK?
UPDATE UPDATE
I need to use AGGREGATIONS.ID_AGGREGATION
because there is another table that has a foreign key to AGGREGATIONS
and to CODES
tables: 我需要使用AGGREGATIONS.ID_AGGREGATION
因为有另一个表具有AGGREGATIONS
和CODES
表的外键:
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])
If I do what you have recommend me in the answer , I will have two columns CODE
in AGGREGATION_CHILDS
table. 如果我在答案中做了你推荐我的事情,我将在AGGREGATION_CHILDS
表中有两列CODE
。 One of them will be foreign key to AGGREGATIONS
table and also to CODES
table. 其中一个是AGGREGATIONS
表的外键,也是CODES
表的外键。 And the other one FK to CODES
table. 而另一个FK到CODES
表。
In one-to-one relationships EF requires the Key of the dependent entity also has to be the Foreign Key to the principal, so, your model would be like this: 在一对一关系中,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; }
}
If you need to use Fluent Api, I think you could do this in the configuration class of Aggregations
: 如果您需要使用Fluent Api,我认为您可以在Aggregations
的配置类中执行此操作:
HasKey(ag=>ag.Code);
HasRequired(ag => ag.Code).WithOptional(c => c.Aggregation);
You can find more info in this page . 您可以在此页面中找到更多信息。
To achieve what you want, you can't declare a FK property in the dependent entity due to the restriction that I comment above. 为了达到你想要的效果,由于我在上面评论的限制,你不能在依赖实体中声明FK属性。 So your model would be like this: 所以你的模型会是这样的:
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; }
}
If you don't want to use Data Annotations you can delete all the attributes and specify the same using Fluent Api in your configuration classes: 如果您不想使用数据注释,则可以删除所有属性,并使用配置类中的Fluent Api指定相同的属性:
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);
}
}
It's not possible specify a composite PK in the AGGREGATION_CHILDS
and configure a one-to-one relationship between this entity and AGGREGATIONS
, unless that composite keys are the keys in AGGREGATIONS
too. 无法在AGGREGATION_CHILDS
指定复合PK并在此实体和AGGREGATIONS
之间配置一对一关系,除非复合键也是AGGREGATIONS
中的键。 If you want to create an one-to-one relationship and specify a FK property in the dependend entity, then that FK must be PK too, so both entity must share the same PK(s). 如果要创建一对一关系并在dependend实体中指定FK属性,那么该FK也必须是PK,因此两个实体必须共享相同的PK。 If you declare another Key in that dependend entity, where is the FK related to another relationship, EF would expect both relationships should be one-to-many (as the example that I show in the Update 1). 如果在该dependend实体中声明另一个Key,其中FK与另一个关系相关,那么EF会期望这两个关系应该是一对多的(就像我在Update 1中显示的那样)。 If you try to create two one-to-one relationships and you try to compound the PK of the dependent end with the PKs of the principals, then you will receive this exception: 如果您尝试创建两个一对一关系,并尝试将从属端的PK与主体的PK复合,那么您将收到以下异常:
AGGREGATION_CHILDS_Aggregation_Source: : Multiplicity is not valid in Role 'AGGREGATION_CHILDS_Aggregation_Source' in relationship 'AGGREGATION_CHILDS_Aggregation'. AGGREGATION_CHILDS_Aggregation_Source ::多重性在关系'AGGREGATION_CHILDS_Aggregation'中的角色'AGGREGATION_CHILDS_Aggregation_Source'中无效。 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'. AGGREGATION_CHILDS_Code_Source ::多重性在关系'AGGREGATION_CHILDS_Code'中的角色'AGGREGATION_CHILDS_Code_Source'中无效。 Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'. 由于“从属角色”属性不是关键属性,因此从属角色的多重性的上限必须为“*”。
I think you're nearly there. 我想你差不多了。 For an Optional Codes.Aggregation
try: 对于一个可选的Codes.Aggregation
尝试:
HasRequired(ag => ag.Code).WithOptional(c => c.Aggregation);
or in your context class: 或者在你的上下文类中:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Aggregations>()
.HasRequired(a => a.Code)
.WithOptional(c => c.Aggregation);
}
This is how I have solved the problem: 这就是我解决问题的方法:
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; }
}
And their maps: 他们的地图:
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
is not relevant here. CODESConfiguration
与此无关。
I have used CODE
as PK on AGGREGATIONS
and on AGGREGATION_CHILDS
and also as FK to CODES
table. 我在AGGREGATIONS
和AGGREGATION_CHILDS
以及FK到CODES
表中使用了CODE
作为PK 。 I have remove ID_AGGREGATION
from AGGREGATIONS
table and remove composite PK on AGGREGATION_CHILDS
table. 我从AGGREGATIONS
表中删除了ID_AGGREGATION
,并删除了AGGREGATION_CHILDS
表上的复合PK 。
I hope it helps someone that have the same problem with One-to-Zero-or-One relationship. 我希望它可以帮助那些在“一对一”或“一对一”关系中遇到同样问题的人。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.