目前,我的实体使用的模型看起来像:
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'.
为什么我会收到此异常?
答案 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; }
然后两个例子中的关系都是必需。