实体框架 - 多对多关系插入重复到父表

时间:2012-11-05 11:12:48

标签: asp.net-mvc entity-framework-5

我正在尝试使用Entity Framework 5进行多对多关系的简单插入。

我有两个POCO课程如下。

public class Category
{
    public virtual string Title { get; set; }
    public virtual DateTime EntryDate { get; set; }
    public virtual DateTime LastUpdated { get; set; }
    public virtual ICollection<Article> Articles { get; set; }
}

public class Article
{
    public virtual string Title { get; set; }
    public virtual string Content { get; set; }
    public virtual DateTime EntryDate { get; set; }
    public virtual DateTime LastUpdated { get; set; }
    public virtual ICollection<Category> Categories { get; set; }
}

以下流畅的api映射代码......

public class CategoryMap : EntityTypeConfiguration<Category>
{
    public CategoryMap()
    {
        this.ToTable("Categories");
        this.HasKey(x => x.ID);

        this.Property(x => x.Title).IsRequired().HasMaxLength(255);
    }
}

public class ArticleMap : EntityTypeConfiguration<Article>
{
    public ArticleMap()
    {
        this.ToTable("Articles");
        this.HasKey(x => x.ID);

        this.HasMany(x => x.Categories)
            .WithMany(x => x.Articles)
            .Map(x =>
            {
                x.ToTable("MapArticleCats");
                x.MapLeftKey("CategoryID");
                x.MapRightKey("ArticleID");
            });

        this.Property(x => x.Title).IsRequired().HasMaxLength(255);
        this.Property(x => x.Content).IsRequired().HasMaxLength(4000);
    }
}

然后,实体框架将生成Category和Article表以及第三个映射表,其中详细信息在ArticleMap代码(MapArticleCats)中指定,在SQL Server中如下所示。

ArticleID - int
CategoryID -int

以下代码(给出或采取几行)将类别添加到我的控制器中的文章。

IEnumerable<Category> GetCats = CategoryRepository.GetAll();

//DO SOME CODE TO FIGURE WHICH CATEGORIES I NEED.
IEnumerable<Category> Categories = InferCategoriesFromPostedData(Model.Categories, GetCats);

foreach (Category c in Categories)
{
    Article.Categories.Add(c);
}

这似乎在插入时会产生一些奇怪的行为。它会在类别表(DUPLICATE)中插入一个新类别,并将新创建的CategoryID(而不是原始ID)和正确的ArticleID插入MapArticleCats表。

谁能看到我出错的地方?

3 个答案:

答案 0 :(得分:4)

确定在提交本文之前我应该​​做的事情(以及之前的那些......非常有罪)是搜索StackOverflow并且更加彻底。

我找到了问题的答案here

发生的事情与上述代码完全无关。这是因为我基本上将两个数据上下文注入我的控制器(一个在文章存储库中,另一个在类别存储库中),因此创建了重复的记录。

<强> ============================================ ======================================
重要编辑
=============================================== ===================================

只是详细说明我的答案......

即使在完成上述修复之后,这仍然无法解决我无法更新导航属性(类别)的原始问题。对此的修复程序如下所示......

我是使用AsNoTracking()绑定实体(文章)的模型,如果您只想更新主实体本身但是您无法对导航属性执行任何操作,则可以。例如在我的案例中添加/删除文章中的类别。

这让我有点蠢蠢,因为我通过从上下文中分离实体尝试了类似的方法,但这两种方式最终给我带来了无法操纵导航属性的同样问题。

解决这个问题的方法只是简单地模拟绑定/选择实体。没有AsNoTracking(),没有分离。当将实体附加回上下文时,请使用以下代码...

    public bool Attach(T entity)
    {
        T original = _dbSet.Find(entity.ID);
        _dbContext.Entry(original).CurrentValues.SetValues(entity);
        _dbContext.Entry(original).State = EntityState.Modified;

        return this.Commit();
    }

这样你就可以在不做任何AsNoTracking / Detaching垃圾的情况下选择它,它会更新得很好。这对我来说没问题,有些人可能会发现额外的数据库攻击有点令人反感,但是为了所有那些适合我的悲伤就好了。

答案 1 :(得分:0)

在dbcontext CaveChanges中调用:

ChangeTracker.DetectChanges()

If ChangeTracker.HasChanges Then
    ChangeTracker.DetectChanges()
End If

这适合我。

答案 2 :(得分:0)

我的问题是我试图将新实例设置为导航属性。

我在做:

IList<Category> categories = _categoryService.GetSomeCategories();
article.Categories = categories;
_articleService.UpdateArticle(article);

相反,你应该坚持现有的ICollection实例,如下所示:

IList<Category> categories = _categoryService.GetSomeCategories();
article.Categories.Clear();
foreach (var category in categories) {
  article.Categories.Add(category);
}
_articleService.UpdateArticle(article);

重复的PRIMARY KEY错误消失了。