如何使用 Navigation 属性 和非标准键?

How to work with Navigation Property and non-standard keys?

假设我有以下数据库 tables 和 1:1 映射

Table dbo.Foo with PrimaryKey FooRowId
Table dbo.Bar with PrimaryKey BarRowId

table 上都不存在外键。

使用 EF,我定义了如下模型。

建模 Foo table

public class Foo
{
    [Key]
    public long FooRowId { get; set; }

    // Navigation
    public virtual Bar Bar { get; set; }
}

造型栏table

public class Bar
{
    [Key]
    public long BarRowId { get; set; }

    // Navigation
    public virtual Foo Foo { get; set; }
}

这给我导航 属性 相关错误如下。

Unable to determine the principal end of an association between the types 'MyOrg.Models.Foo' and 'MyOrg.Models.Bar'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.

一种解决方法是按如下方式标准化 属性 名称。

在福

public class Foo
{
    [Key]
    [Column("FooRowId")]
    public long FooId { get; set; }

    // Navigation
    public virtual Bar Bar { get; set; }
}

酒吧

public class Bar
{
    [Key]
    [Column("BarRowId")]
    public long BarId { get; set; }

    // Navigation
    public virtual Foo Foo { get; set; }
}

但是,要求声明我必须保留原始属性 FooRowIDBarRowId。鉴于此约束,如何使导航属性起作用?

虽然属性看起来易于使用,但它限制了您的 classes 在其他数据库中的重用。

假设您已经根据贵公司(可能是国家/地区)的标准创建了一个 class BillingAddress。您想要在两个不同的 DbContext 中使用此 class,每个都代表自己的数据库。数据库 1 中的 BillingAddress 在 "MyPrimaryKey" 列中有一个主键,数据库 2 中的 BillingAddress 在 "Id" 列中有一个主键。您无法使用属性解决该问题。

列名和tables,tables之间的关系是数据库的一部分。因此,这应该在 DbContext 中进行描述。如果您不在 DbSet classes 中使用属性,您将能够在不同的数据库中使用相同的 class。

所以让我们用流利的语言编写您的 table 设计 Api

参见:

下面我给出了所有三个类别的示例:

  • 配置table名称和table
  • 的主键
  • 配置属性之一:列名
  • 配置table之间的关系,例如一对多

请记住:如果您首先使用代码,并且坚持 the entity framework code first conventions,则需要 none。只要您遵守这些约定,Entity Framework 将非常有能力检测主键、外键、table 之间的关系。

但是如果你的table不一样,你的DbContext

需要下面的fluentAPI
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
     // Configure entity table FOO:
     var entityFoo = modelBuilder.Entity<Foo>();

     // example: configure Name and primary key of foo table
     entityFoo.ToTable("MySpecialFooTable");
     entifyFoo.HasKey(foo => foo.FooRowId);

     // example: configure property Name is in column FooName:
     entityFoo.Property(foo => foo.Name).HasColumnName("MyFooName");

     // example: one-to-many relation between foo and bar
     // every Foo has zero or more Bars in property MyBars,
     // every Bar belongs to exactly one For in property MyFoo
     // using foreign key MyFooId:
     entityFoo.HasMany(foo => foo.MyBars)         // Foo has zero or more Bars in MyBars
              .WithRequired(bar => bar.MyFoo)     // every Bar belongs to one Foo
              .HasForeignKey(bar => bar.MyFooId); // using foreign key MyFooId
}