附加具有导航属性的实体时出现异常

时间:2015-01-23 22:03:57

标签: c# asp.net-mvc entity-framework many-to-many

我有实体ExhibitExhibition,它们是多对多的关系。 Exhibit也可以有多个类别。

public class ExhibitionModel
{
    public ExhibitionModel()
    {
        this.Exhibits = new List<ExhibitModel>();
    }

    [Key]
    public int ExhibitionId { get; set; }

    //some props

    public virtual IList<ExhibitModel> Exhibits { get; set; }
}

public class ExhibitModel
{
    [Key]
    public int ExhibitId { get; set; }

    //some props

    public virtual IList<CategoryModel> Categories { get; set; }
    public virtual IList<ExhibitionModel> Exhibitions { get; set; }
}

public class CategoryModel
{
    [Key]
    public int CategoryId { get; set; }

    public virtual IList<ExhibitModel> Exhibits { get; set; }
}

当我创建一个新的展览时,在我的ViewModel中,我有所有的展览参数和字符串,其中包含选定的展品ID。

    public ActionResult Create(CreateExhibitionViewModel model)
    {
        try
        {
            if (ModelState.IsValid)
            {
                if (!String.IsNullOrEmpty(model.ExhibitsString))
                {
                    model.Exhibition.AddExhibitsToModel(model.ExhibitsString, exhibitsRepo);
                }

                var result = exhibitionsRepo.Create(model.Exhibition);
                if (result != null)
                {
                    return RedirectToAction("Index");
                }
            }
            return View(model);
        }
        catch
        {
            return View();
        }
    }

    public static void AddExhibitsToModel(this ExhibitionModel model, string exhibitsString, ExhibitsRepository exhibitsRepo)
    {
        if (!String.IsNullOrEmpty(exhibitsString))
        {
            string[] ids = exhibitsString.Split(',');
            foreach (string stringId in ids)
            {
                int id;
                ExhibitModel exhibit = new ExhibitModel();
                if (int.TryParse(stringId, out id))
                {
                    exhibit = exhibitsRepo.Read(id);
                }

                model.Exhibits.Add(exhibit);
            }
        }
    }

来自Create

ExhibitionRepository方法
    public ExhibitionModel Create(ExhibitionModel exhibition)
    {
        try
        {
            using (var dbContext = new MuseumContext())
            {
                foreach (var exhibit in exhibition.Exhibits)
                {
                    if (exhibit.ExhibitId != 0 && dbContext.Entry(exhibit).State == EntityState.Detached)
                    {
                        dbContext.Exhibits.Attach(exhibit);
                    }
                }

                var result = dbContext.Exhibitions.Add(exhibition);
                dbContext.SaveChanges();
                return result;
            }
        }
        catch (Exception ex)
        {
            return null;
        }
    }

正如您所看到的,我正在附加每个展览实体以避免创建新记录。当两个展品具有相同的类别时,附加第二个展览会抛出异常

  

附加“Project.Models.CategoryModel”类型的实体失败,因为同一类型的另一个实体已具有相同的主键值。如果图中的任何实体具有冲突的键值,则在使用“附加”方法或将实体的状态设置为“未更改”或“已修改”时,可能会发生这种情况。这可能是因为某些实体是新的并且尚未收到数据库生成的键值。在这种情况下,使用“添加”方法或“已添加”实体状态来跟踪图表,然后根据需要将非新实体的状态设置为“未更改”或“已修改”。

我该怎么做才能解决这个问题?

此致 康拉德

1 个答案:

答案 0 :(得分:0)

当EF已经跟踪实体时,通常会发生此错误。我想它可能在这里:

exhibit = exhibitsRepo.Read(id);

您有两种选择。

  1. 您可以使用AsNoTracking()设置Read方法。 也许db.Exhibits.AsNoTracking().Where(x => x.Id== id);

    这样您就明确告诉EF不要跟踪实体。

  2. 如果展品已经在数据库中,只需将它们添加到展览馆藏并保存更改,EF就会为您制作并保存参考(在展品记录中)。 无需重新附加实体。