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 表中。

谁能看到我哪里出错了?

4

3 回答 3

4

好的,在提交这篇文章(以及以前的文章......非常有罪)之前我应该​​做的是搜索 StackOverflow 并更彻底地搜索。

我在这里找到了我的问题的答案

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

==================================================== =================================
重要编辑
================ ==================================================== =================

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

即使在完成上述修复后,这仍然没有解决我无法更新导航属性(类别)的原始问题。解决方法如下...

我正在使用 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 垃圾的情况下选择它,它会更新得很好。这对我来说没问题,有些人可能会觉得额外的 db 之旅有点令人反感,但为了所有适合我的悲伤。

于 2012-11-05T12:16:44.010 回答
0

在您的 dbcontext CaveChanges 调用中:

ChangeTracker.DetectChanges()

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

这对我有用。

于 2013-11-21T13:41:56.110 回答
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 错误消失了。

于 2014-01-15T10:50:36.723 回答