为什么向我的EF4.1 Code First实体添加显式外部ID列会导致外键约束冲突?

时间:2011-03-29 22:43:09

标签: c# entity-framework code-first entity-framework-4.1

目前,我的实体使用的模型看起来像:

public class MyModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }

    public virtual User User { get; set; }
}

这样做很好,但是我一直看到CodeFirst示例,它为模型中的外来实体显式创建了Id属性。这是有道理的,所以我不必懒惰加载用户来检索与MyModel实例关联的用户的id值。

但是,当我将MyModel更改为:

public class MyModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }

    public virtual int UserId { get; set; }
    public virtual User User { get; set; }
}

尝试提交MyModel个实例时,我收到以下异常:

System.Data.SqlClient.SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "MyModel_User". The conflict occurred in database "mjlunittest", table "dbo.Users", column 'Id'.

为什么我会收到此异常?

1 个答案:

答案 0 :(得分:4)

当您从第一个MyModel示例移到第二个示例时,EF Code-First约定检测到一个重要更改:

在第一种情况下,模型中没有外键属性,关系MyModel -> User 可选,因为User中的属性MyModel can - 作为对另一个对象的引用 - 为null。因此,EF约定将在数据库中创建可空外键列。

在第二种情况下,您告诉EF您的外键UserId类型为int 不可为空。因此,EF约定规则会将MyModel -> User关系视为 required ,并在数据库中创建一个不可为空的Int32列。

如果您创建第二个版本类型MyModel的对象,将其添加到上下文并调用SaveChanges,您将获得您所描述的异常 - 除非您在数据库中有一个带有外键的用户(如果在创建对象时未指定其他值,则必须为0)。创建和保存第一个版本的对象不会抛出此异常,因为此处允许数据库中的外键为null

如果您希望MyModel的两个示例的行为方式相同,则可以在第二个示例中将外键属性设置为可为空:

public virtual int? UserId { get; set; }

然后,MyModel的两个示例中的关系都是可选

或者您可以在第一个示例中提供User属性:

[Required]
public virtual User User { get; set; }

然后两个例子中的关系都是必需