简体   繁体   English

一对一或零关系,其中FK是依赖表上的复合PK的一部分

[英]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>上设置AGGREGATIONSCODES之间的关系:

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因为有另一个表具有AGGREGATIONSCODES表的外键:

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 . 您可以在此页面中找到更多信息。

Update 1 更新1

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);

    }
 }

Update 2 更新2

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. 我在AGGREGATIONSAGGREGATION_CHILDS以及FKCODES表中使用了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.

相关问题 EF代码优先-在不共享PK / FK的情况下配置一对零或一对关系 - EF code first - configure One-to-Zero-or-One relationship without shared PK/FK 如何配置这种一对零或一的关系? - How to configure this one-to-zero-or-one relationship? 使用CodeFirst的C#一对零或一个关系 - C# One-To-Zero-Or-One relationship using CodeFirst Code First EF5:One-to-Zero-One关系不起作用 - Code First EF5: One-to-Zero-or-One relationship is not working 与FK的一对一关系不同于PK - One-To-One relationship with FK distinct from PK 使用EF7映射一对一或一 - Mapping One-to-Zero-or-One with EF7 如何使用两端的导航属性正确创建EF一对零或一个关系? - How to properly create an EF One-to-Zero-or-One relationship with navigation properties on both ends? 实体框架(EF)代码优先级联删除一对一或零关系 - Entity Framework (EF) Code First Cascade Delete for One-to-Zero-or-One relationship 列不是主键时与EF Code First的一对零或一对关系 - One-to-Zero-or-One relationship with E.F. Code First when column is not primary key 创建具有两个子表的主表,这些子表将EF 4.1一对一或零链接 - Creating a master table with two child tables linking one-to-zero-or-one with EF 4.1
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM