实体框架 - 使用相同密钥

时间:2015-08-11 17:29:45

标签: c# sql-server asp.net-mvc entity-framework ef-code-first

我已经在这个主题上阅读了尽可能多的帖子,但我尝试过的解决方案似乎都没有。我有一个现有的数据库,并创建了一个新的Code First From Existing Database项目。

我有一个名为Thing的基表。每个对象在此表中都有一条记录,使用Id作为唯一主键。每个其他对象都继承自此,但它们在子表中使用相同的Id,而不在子表中使用新的Identity列。有效地给每个'Thing'一个唯一的ID:

public class Thing
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class Car
{
    public int Id { get; set; }
    //other properties
}

public class Person
{
    public int Id { get; set; }
    //other properties
}

public class Color
{
    public int Id { get; set; }
    //other properties
}

每个新记录首先在'Thing'中创建一个项目,然后使用该Id值在其各自的表中创建一个新记录,创建多个1到0..1关系,其中派生表上的Id字段也是FK到了事。

东西1到0..1车

事情1到0..1人

东西1到0..1颜色

等等

我尝试了许多不同的Data Annotation和Fluent API组合,但它总是会回到同样的错误:

  

'无法检索Model.Car的元数据'。无法确定类型'Model.Thing'和'Model.Car'之间的主要关联结束。必须使用关系流畅API或数据注释显式配置此关联的主要结尾。'

我确实设法通过使用带有反向注释的虚拟并将Id字段设置为Key和ForeignKey来解决此错误,但随后消息跳转到Person。如果您将其设置为与Car相同,则消息将恢复为Car。

似乎我可以回去为每个子表创建一个正常的外键,但这是很多工作,我相信有可能以某种方式使这个工作。最好使用流畅的API。

1 个答案:

答案 0 :(得分:0)

如果您要使用数据注释,您还需要将依赖实体的PK声明为FK:

public class Thing
{
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual Car Car{get;set;}
}

public class Car
{
    [Key,ForeignKey("Thing")]
    public int ThingId { get; set; }
    //other properties

    public virtual Thing Thing{get;set;}
}

如果您打算使用Fluent Api(从模型中删除属性),配置将如下所示:

modelBuilder.Entity<Car>().HasRequired(c=>c.Thing).WithOptional(t=>t.Thing);

根据指定的多重性,只有Thing成为主体且Car成为依赖,才有意义,因为Thing可以在没有{{1}的情况下存在但是Car必须有Car

正如您所看到的,您不需要指定Thing是此关系的FK。这是因为Entity Framework要求将依赖项的主键用作外键。由于没有选择,Code First会为您推断出这一点。

更新

再次阅读您的问题我认为您正在尝试创建层次结构。在这种情况下,您可以使用Table per Type (TPT)方法。