完整插入/更新/删除实体框架中的子实体 [英] Complete Insert/Update/Delete of Child Entities in Entity Framework

查看:116
本文介绍了完整插入/更新/删除实体框架中的子实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道以前有人问过,但是经过长时间的搜索和编码,我无法得到一个工作和干净的方法。这是我有的:

  public class QuestionModel 
{
public int QuestionID {get;组; }
public string QuestionText {get;组; }

public IList< QuestionChoiceModel>选择{get;组; }
}

public class QuestionChoiceModel
{
public int ChoiceID {get;组; }
public string ChoiceText {get;组;
}

我在这个ASP.Net MVC应用程序中使用EF 5。使用 InRequestScope()的Ninject的通用存储库模式和依赖注入已到位并且工作顺利。这些模型被映射到实体而没有问题。



向数据库添加新问题是直截了当的。我设置了一些QuestionChoice实例的Question属性,EF处理其余的。



问题是关于更新。假设我们在数据库中有一个Question 3的问题:

  ChoiceID QuestionID ChoiceText 
-------- ---------- ----------
1 1 blah blah
2 1 blah blah
3 1 blah blah

当问题的编辑页面打开(GET:/ Questions / Edit / 1)时,我使用<$剃须刀中的c $ c> foreach 我已经写了一些JQuery代码,如果用户想要添加或删除输入元素所需的标记。因此,ID = 1的QuestionChoice可能会在客户端编辑,ID = 2可能会被删除,并且可能会添加一个新的ID = 4。当用户按下保存按钮(POST:/ Questions / Edit / 1)时,表单数据完全绑定到一个QuestionModel。该模型正确映射到问题实体。这就是故事的开始!



现在Question实体有一个QuestionChoices的集合,其中一些已经在数据库中,有些应该添加到数据库中,有些应该是从数据库中删除。



我读过很多帖子,如:
实体框架不保存修改的子项



我可以处理那种脏的方式的编辑。还有新记录:

  this._context.Entry(choice).State = EntityState.Added; 

但我正在寻找一个更优雅的方式。并处理应该删除的记录。在这种情况下使用EF可以处理完整的插入/更新/删除子实体的好方法吗?老实说,我预计从EF更多。

解决方案

这是一个棘手的问题。不幸的是,我不能提供你喜欢的解决方案。我不相信是可能的。 EF无法跟踪对您的实体所做的更改,除非它们是在检索实体的上下文中进行的 - 这在Web环境中是不可能的。唯一可行的方法是在POST到/ Questions / Edit / 1之后检索Question对象(在上下文中),并在POSTed Question和POSTed Question之间执行一个merge类型数据库。这将包括使用您的POSTed 从数据库中检索到的 QuestionModel 和每个 QuestionChoiceModel QuestionModel 。我会说,这不是很好的做法,因为你会忘记包括一个财产。这将会发生。



我可以提供的最好的(最简单的)解决方案是添加/编辑你的 QuestionModel QuestionChoiceModel(s)使用上面的 .Entry()方法。您将牺牲这里的最佳实践,以获得更少的错误解决方案。

  QuestionModel questionFromDb; 
QuestionModel questionFromPost;

QuestionModelChoice [] deletedChoices = questionFromDb.Choices.Where(c =>!questionFromPost.Choices.Any(c2 => c2.Id == c.Id));


使用(var db = new DbContext())
{
db.Entry(questionFromPost).State = questionFromPost.Id == 0? EntityState.Added:EntityState.Modified;

foreach(var choice in questionFromPost.Choices)
{
db.Entry(choice).State = choice.Id == 0? EntityState.Added:EntityState.Modified;
}

foreach(var deletedChoice in deletedChoices)
{
db.Entry(deletedChoice).State = EntityState.Deleted;
}

db.SaveChanges();
}


I know it has been asked before, but after long hours of searching and coding I can't get to a working and clean approach. Here is what I have:

public class QuestionModel
{
    public int QuestionID { get; set; }
    public string QuestionText { get; set; }

    public IList<QuestionChoiceModel> Choices { get; set; }
}

public class QuestionChoiceModel
{
    public int ChoiceID { get; set; }
    public string ChoiceText { get; set; }
}

I'm using EF 5 for this ASP.Net MVC application. Generic Repository Pattern and Dependency Injection with Ninject using InRequestScope() are in place and work smoothly. These models are mapped to/from entities without a problem.

Adding new Questions to database is straight forward. I set Question property of some QuestionChoice instances, and EF handles the rest.

The problem is about updates. Assume we have a Question in database with 3 QuestionChoices:

ChoiceID    QuestionID    ChoiceText
--------    ----------    ----------
1           1             blah blah
2           1             blah blah
3           1             blah blah

When edit page of a Question opens (GET: /Questions/Edit/1), I show these 3 choices using a foreach in Razor. I've written some JQuery code that adds or deletes required markup for input elements if user wants to. So, the QuestionChoice with ID=1 might be edited on client, ID=2 might be deleted, and a new ID=4 might be added. The form data is bound back to a QuestionModel perfectly when user presses the Save button (POST: /Questions/Edit/1). The model is mapped to a Question entity correctly. That is where the story begins!

Now the Question entity has a collection of QuestionChoices some of which are already in database, some should be added to database, and some should be deleted from database.

I've read many posts like: Entity Framework not saving modified children

I can handle edits in that dirty way. And also new records by:

this._context.Entry(choice).State = EntityState.Added;

But I'm looking for a more elegant way. And also handle records that should be deleted. Is there a good approach to handle complete insert/update/delete of child entities in this scenario using EF? Honestly, I expected more from EF.

解决方案

This is a tough problem. Unfortunately, I cannot offer the solution that you prefer. I do not believe it is possible. EF cannot track changes made to your entities unless they are made within the context that the entities are retrieved - which is impossible in a web environment. The only way for this to be possible would be to retrieve the Question object (within a context) after the POST to /Questions/Edit/1, and to perform a type of "merge" between the POSTed Question, and the Question retrieved from the database. This would include assigning properties on your QuestionModel and each QuestionChoiceModel retrieved from the database using your POSTed QuestionModel. I will say that this wouldn't be great practice either, because you WILL forget to include a property. It will happen.

The best (and easiest) solution I can provide would be to add/edit your QuestionModel and QuestionChoiceModel(s) using the .Entry() method above. You will sacrifice "best practice" here for a solution that will be less error-prone.

QuestionModel questionFromDb;
QuestionModel questionFromPost;

QuestionModelChoice[] deletedChoices = questionFromDb.Choices.Where(c => !questionFromPost.Choices.Any(c2 => c2.Id == c.Id));


using (var db = new DbContext())
{
    db.Entry(questionFromPost).State = questionFromPost.Id == 0 ? EntityState.Added : EntityState.Modified;

    foreach(var choice in questionFromPost.Choices)
    {
        db.Entry(choice).State = choice.Id == 0 ? EntityState.Added : EntityState.Modified;
    }

    foreach(var deletedChoice in deletedChoices)
    {
        db.Entry(deletedChoice).State = EntityState.Deleted;
    }

    db.SaveChanges();
}

这篇关于完整插入/更新/删除实体框架中的子实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆