具有单独ID属性的EF6一对一关系

时间:2018-01-18 08:28:37

标签: c# .net entity-framework

我们需要在以下实体之间定义一对一关系:

public class Foo
{
    [Key, Column("Foo_ID")]
    public int Id { get; set; }

    public Bar Bar { get; set; }
}

public class Bar
{
    [Key, Column("Bar_ID")]
    public int Id { get; set; }

    [Column("Bar_Foo_ID")]
    public int? FooId { get; set; }

    public Foo Foo { get; set; }   
}

我们需要迁移旧版软件并暂时并行运行。所以我们无法改变任何关系。不幸的是,数据库中没有定义外键。

modelBuilder.Entity<Foo>()
            .HasOptional(a => a.Bar)
            .WithRequired(x => x.Foo)
            .WillCascadeOnDelete(true);

当我们查询FooInclude(x => x.Bar)时,它会创建一个LEFT OUTER JOIN bars ON Foo_ID = Bar_ID的SQL查询,这是错误的。

我们需要将其更改为LEFT OUTER JOIN bars on Foo_ID = Bar_Foo_ID,但我不确定实体框架是如何支持的,因为我们的数据库中没有外键,而Bar_ID则为PrimaryKey

我知道一个Bars可能有多个Foo,但有没有办法强制实行一对一关系?

创建Foo后,始终会为其创建Bar

2 个答案:

答案 0 :(得分:2)

对于旧数据,您可以使用以下内容:

1:0-1关系基本上是1:多种关系的特殊形式。

因此,您可以在实体框架中将关系配置为1:many,并可能向外键属性添加唯一索引以强制执行max的约束。一个相关的条目。

public class Foo
{
    [Key, Column("Foo_ID")]
    public int Id { get; set; }

    // this can't be a single reference property unfortunately... but it will only contain 0 or 1 object when working with it.
    public ICollection<Bar> Bars { get; set; }
}

public class Bar
{
    [Key, Column("Bar_ID")]
    public int Id { get; set; }

    [Index(IsUnique = true)]
    [Column("Bar_Foo_ID")]
    public int? FooId { get; set; }

    public Foo Foo { get; set; }   
}

modelBuilder.Entity<Foo>()
            .HasMany(a => a.Bars)
            .WithRequired(x => x.Foo)
            .HasForeignKey(x => x.FooId)
            .WillCascadeOnDelete(true);

答案 1 :(得分:1)

我理解它的方式,你在Bar_Foo_ID表中有一个名为Bar的列,它必须用作Bar_ID表中PK Bar列的FK

这是可能的,但EF6对这种关系的支持有限,特别是不支持显式FK属性。因此,您必须从模型中删除FooId属性:

public class Bar
{
    [Key, Column("Bar_ID")]
    public int Id { get; set; }

    public Foo Foo { get; set; }   
}

并使用以下流畅配置:

modelBuilder.Entity<Foo>()
    .HasOptional(a => a.Bar)
    .WithOptionalPrincipal(x => x.Foo)
    .Map(m => m.MapKey("Bar_Foo_ID"))
    .WillCascadeOnDelete(true);

MapKey用于指定FK列名称。 WithOptionalPrincipal是指定它可以为空(而WithRequired是非可空的。)

请注意,对于可选关系,EF6会以不同方式处理级联删除。它不是删除相关记录,而是通过将FK设置为​​null来取消关联。如果您想在删除Bar时实际删除关联的Foo,则必须使用代码手动执行此操作。