实体框架,带有必需引用的奇怪行为,延迟加载

时间:2012-09-21 06:44:11

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

这适用于实体框架4(4.3.1)和5。

我有一个User类(与我的Entity Framework MembershipProvider一起使用)。我删除了一些属性来简化。实际用户来自MVCBootstrap项目,因此它不是与其他类相同的程序集的一部分。

public class User {
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }
    [Required]
    [StringLength(256)]
    public String Username { get; set; }
}

然后我有这个课程:

public class NewsItem {
    public Int32 Id { get; set; }
    [Required]
    [StringLength(100)]
    public String Headline { get; set; }
    [Required]
    public virtual User Author { get; set; }
    [Required]
    public virtual User LastEditor { get; set; }
}

然后我创建数据库上下文(用户的DbSet在MembershipDbContext中):

public class MyContext : MVCBootstrap.EntityFramework.MembershipDbContext {
    public MyContext(String connectString) : base(connectString) { }
    public DbSet<NewsItem> NewsItems { get; set; }
}

在创建数据库时,运行此代码会给我这个异常:

  

在表'WebShop'上引入FOREIGN KEY约束'FK_dbo.WebShop_dbo.User_LastEditor_Id'可能会导致循环或多个级联路径。指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束。   无法创建约束。查看以前的错误。

所以我改变了数据库上下文:

public class MyContext : MVCBootstrap.EntityFramework.MembershipDbContext {
    public MyContext(String connectString) : base(connectString) { }
    public DbSet<NewsItem> NewsItems { get; set; }
    protected override void OnModelCreating(DbModelBuilder modelBuilder) {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Configurations.Add(new NewsItemConfiguration());
    }
}

这个配置:

public class NewsItemConfiguration : EntityTypeConfiguration<NewsItem> {
    public NewsItemConfiguration() {
        HasRequired(n => n.Author).WithOptional();
        HasRequired(n => n.LastEditor).WithOptional();
    }
}

或者这是错的?

无论如何,当我运行代码时,数据库得到了创建,数据库似乎没问题(查看外键约束等)。

但是,然后我从上下文中获取了10个最新的NewsItem,并开始将它们加载到视图模型中,其中一部分是访问NewsItem上的Author属性。执行此操作的控制器需要永久加载,并在很长很长时间后失败。在调试模式下运行时,我在这段代码中得到一个例外:this.AuthorId = newsItem.Author.Id;,然后我得到的例外是:

  

发生了关系多重性约束违规:EntityReference只能有一个相关对象,但查询返回了多个相关对象。这是一个不可恢复的错误。

这可能是一些简单而愚蠢的事我做错了,我确信我已经在几个网站上运行了类似的代码,所以..是什么导致这个?我的模型是错误的,是数据库上下文,还是?

2 个答案:

答案 0 :(得分:0)

这部分

  

介绍FOREIGN KEY约束&#39; FK_dbo.WebShop_dbo.User_LastEditor_Id&#39;在桌面&#39; WebShop&#39;可能会导致循环或多个级联路径。指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束。无法创建约束。查看以前的错误。

实际上是一个SQL Server问题(以及许多其他RDBMS的问题)。解决多个级联路径是一个复杂的问题,而SQL Server决定只是试图而不是尝试。参见

Foreign key constraint may cause cycles or multiple cascade paths?

您尝试将模型配置为在删除NewsItem时删除子Author和LastEditor对象。 SQL Server不会这样做。

想一想......你想要的是什么?看来你想要将Author和LastEditor与NewsItem取消关联,而不是将它们从数据库中删除。

您的对象模型需要NewsItem和Author之间以及NewsItem和LastEditor之间的1:1关系。我不确定这个在代码

中引用了什么
this.AuthorId = newsItem.Author.Id;

但在我看来,你应该以相反的方式进行分配,例如

newsItem.Author = myAuthorInstance;

或者如果您在模型中包含外键属性,并且之前已保存过您的作者实例并且具有Id:

newsItem.AuthorId = myAuthorInstance.Id; 

如果您共享生成的数据库架构(相关部分),以便更容易诊断问题。

答案 1 :(得分:0)

用户可以是多个新闻项目的作者。此外,用户可以编辑多个新闻项目 因此,关系必须是“一对多”:

public class NewsItemConfiguration : EntityTypeConfiguration<NewsItem> {
    public NewsItemConfiguration() {
        HasRequired(n => n.Author).WithMany();
        HasRequired(n => n.LastEditor).WithMany();
    }
}