首页 文章

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

提问于
浏览
3

我正在尝试使用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 回答

  • 3

    好吧,在提交这篇文章之前我应该做的事情(以及之前的那些...大规模有罪)是搜索StackOverflow并且更加彻底 .

    我找到了问题的答案here

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

    ==================================================================================
    IMPORTANT EDIT
    ==================================================================================

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

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

    我是使用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垃圾,它会更新得很好 . 这对我来说没问题,有些人可能会发现额外的数据库攻击有点令人反感,但为了所有那些适合我的悲伤就好了 .

  • 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错误消失了 .

  • 0

    在dbcontext CaveChanges调用中:

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

    这对我有用 .

相关问题