如何避免EF中新添加的记录的乐观并发错误

时间:2022-01-03 06:50:04

I use Entity Framework 6 in an MVC 5 project an there is an entity relations between Experiment and FileAttachment (one Experiment can gave many FileAttachment). During Edit an Experiment record, I load a ViewModel containing both of the entities and list the attachments under the experiment in edit mode:

我在MVC 5项目中使用Entity Framework 6,在Experiment和FileAttachment之间存在实体关系(一个实验可以提供许多FileAttachment)。在编辑实验记录期间,我加载包含两个实体的ViewModel,并在编辑模式下列出实验下的附件:

The scenario is as explained below:

场景如下所述:

1) There is a Delete button for each FileAttachment and when user delete an attachment, it is deleted via AJAX and display an information message on the same modal window.

1)每个FileAttachment都有一个Delete按钮,当用户删除附件时,它将通过AJAX删除并在同一模态窗口中显示信息消息。

2) But, if the user add a new attachment after deleting an attachment and save the Experiment the following error is encountered:

2)但是,如果用户在删除附件后添加新附件并保存实验,则会遇到以下错误:

"Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded."

“存储更新,插入或删除语句影响了意外的行数(0)。实体可能已被修改或删除,因为实体已加载。”

  • I think the reason is that: I load Experiment and FileAttachment entities and then I change the FileAttachment entity by deleting a record. But there is still the same entity loaded first time and I want to save the outdated entity. So, maybe I need to create an entity and fill it before saving, but context.Entry(f).State = EntityState.Added, context.Entry(f).State = EntityState.Modified and context.Entry(f).State = EntityState.Unchanged does not make any sense. What should I do to simply attach the newly added FileAttachment to the database?
  • 我认为原因是:我加载Experiment和FileAttachment实体,然后通过删除记录来更改FileAttachment实体。但是第一次仍然存在相同的实体,我想保存过时的实体。所以,也许我需要创建一个实体并在保存之前填充它,但context.Entry(f).State = EntityState.Added,context.Entry(f).State = EntityState.Modified和context.Entry(f).State = EntityState.Unchanged没有任何意义。如何将新添加的FileAttachment附加到数据库?

Models:

public class Experiment
{
    [Key]
    public int Id { get; set; }

    public int Number { get; set; }

    public string Name { get; set; }

    //Navigation Properties 
    public virtual ICollection<FileAttachment> FileAttachments { get; set; }
}



public class FileAttachment
{
    [Key]
    public int Id { get; set; }

    public int ExperimentId { get; set; }

    public string FileName { get; set; }

    public byte[] FileData { get; set; }

    [HiddenInput(DisplayValue = false)]
    public string FileMimeType { get; set; }

    //Navigation Properties 
    public virtual Experiment Experiment { get; set; }
}

ViewModel:

public class ExperimentViewModel
{
    //code omitted for brevity

    [DataType(DataType.Upload)]
    public IEnumerable<HttpPostedFileBase> FileUpload { get; set; }

    public virtual ICollection<FileAttachment> FileAttachments { get; set; }
}

Controller:

public JsonResult Update([Bind(Exclude = null)] ExperimentViewModel model)
{
    List<FileAttachment> fa = new List<FileAttachment>();
    //code omitted for brevity (At this step I add all the attachments in the model to "fa" paarmeter)

    //Mapping ViewModel to Entity Model (ExperimentViewModel > Experiment) :::::::::::::::::
    var config = new MapperConfiguration(cfg =>
    {
        cfg.CreateMap<ExperimentViewModel, Experiment>();
    });

    IMapper mapper = config.CreateMapper();
    //var source = new ExperimentViewModel();
    var dest = mapper.Map<ExperimentViewModel, Experiment>(model);
    ////::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

    repository.SaveExperimentWithAttachment(dest, fa);
}

Concrete:

public void SaveExperimentWithAttachment(Experiment experiment, IEnumerable<FileAttachment> fileAttachment)
{ 

    //Update Block 
    using (var context = new EFDbContext())
    {
        context.Entry(experiment).State = EntityState.Modified;
        foreach (FileAttachment f in fileAttachment)
        {
            context.Entry(f).State = EntityState.Modified;
        }
        context.SaveChanges(); 
    }
}


1 个解决方案

#1


0  

Here is the final answer by fixing the problems with the help of @StephenMuecke and @haim770. Many thanks both of you for your effort and kind help... Regards.

这是在@StephenMuecke和@ haim770的帮助下修复问题的最终答案。非常感谢你们的努力和善意的帮助......问候。

public void SaveExperimentWithAttachment(Experiment experiment, IEnumerable<FileAttachment> fileAttachment)
{
    using (var context = new EFDbContext())
    {
        context.Entry(experiment).State = EntityState.Modified;
        foreach (FileAttachment f in fileAttachment)
        {
            // !!! I forgot to update the ExperimentId field for each file attachment
            f.ExperimentId = experiment.Id;
            context.Entry(f).State = EntityState.Added; //Because file attachment(s) is not updated, newly ADDED
        }
        context.SaveChanges();
    }
}

#1


0  

Here is the final answer by fixing the problems with the help of @StephenMuecke and @haim770. Many thanks both of you for your effort and kind help... Regards.

这是在@StephenMuecke和@ haim770的帮助下修复问题的最终答案。非常感谢你们的努力和善意的帮助......问候。

public void SaveExperimentWithAttachment(Experiment experiment, IEnumerable<FileAttachment> fileAttachment)
{
    using (var context = new EFDbContext())
    {
        context.Entry(experiment).State = EntityState.Modified;
        foreach (FileAttachment f in fileAttachment)
        {
            // !!! I forgot to update the ExperimentId field for each file attachment
            f.ExperimentId = experiment.Id;
            context.Entry(f).State = EntityState.Added; //Because file attachment(s) is not updated, newly ADDED
        }
        context.SaveChanges();
    }
}