c# - 一对零或一关系,其中 FK 是从属表上的复合 PK 的一部分

标签 c# entity-framework fluent

我正在使用 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])
)

关系:

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

我试过这个来设置AGGREGATIONS之间的关系和 CODES关于聚合的 EntityTypeConfiguration<AGGREGATIONS> :

HasKey(ag => ag.ID_AGGREGATION);
HasRequired(ag => ag.Code).WithOptional(c => c.Aggregation);

但是我不知道怎么设置AGGREGATIONS.CODE作为此关系中的外键。

如何在此关系上设置 FK?

更新

我需要使用 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])

如果我按照您在 answer 中推荐我的方式进行操作,我将有两列 CODEAGGREGATION_CHILDS table 。其中之一将是 AGGREGATIONS 的外键表和 CODES table 。另一个 FK 到 CODES表。

最佳答案

在一对一关系中,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的配置类中这样做:

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 指定相同的属性:

 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 之间配置一对一关系,除非复合键是聚合也是。如果要创建一对一关系并在依赖实体中指定 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 '*'.

关于c# - 一对零或一关系,其中 FK 是从属表上的复合 PK 的一部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29011682/

相关文章:

c# - 无法使用 LINQ OrderBy 中的属性名称进行排序

entity-framework - 将 Entity Framework 实体集合从 DAL 传递到业务层的最佳方法?

c# - 使用 Fluent api 进行 3 种方式的多对多

c# - 最佳年龄算法?

c# - 如何在 C# 中将 DateTime 转换为 shortdatetime?

c# - 如何统一创建可横向滚动的二维地形?

c - 从 Windows 到 Linux 的语法错误 Fluent UDF

c# - 检查屏幕上是否显示 Vector3

c# - 为什么 .Contains 很慢?通过主键获取多个实体的最有效方法?

java - 如何删除 Fluent 界面默认方法的未检查警告