war*_*990 11 c# entity-framework entity-framework-6
假设您的实体中有这些类.
public class Parent
{
public int ParentID { get; set; }
public virtual ICollection<Child> Children { get; set; }
}
public class Child
{
public int ChildID { get; set; }
public int ParentID { get; set; }
public virtual Parent Parent { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
并且您有一个用户界面来更新Parent它Children,这意味着如果用户添加新的,Child那么您必须插入,如果用户编辑现有的Child则需要更新,如果用户删除了Child则必须删除.现在很明显,如果您使用以下代码
public void Update(Parent obj)
{
_parent.Attach(obj);
_dbContext.Entry(obj).State = EntityState.Modified;
_dbContext.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)
它将无法检测到内部的更改,Child因为EF无法检测到导航属性中的更改.
我一直在问这个问题4次,得到的答案很复杂.那么实际上可以做到这一点而不会变得复杂吗?这个问题可以通过分离之间的用户界面解决问题Parent和Child,但我不想因为两者合并Child,并Parent在一个菜单是企业应用开发和用户更加友好很常见.
更新:我正在尝试下面的解决方案,但它不起作用.
public ActionResult(ParentViewModel model)
{
var parentFromDB = context.Parent.Get(model.ParentID);
if (parentFromDB != null)
{
parentFromDB.Childs = model.Childs;
}
context.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)
EF不会检测孩子内部的变化,也无法说明如何处理孩子.例如,如果parentFromDB我第一次从DB中取出3个孩子,那么我会删除第2个和第3个孩子.然后我The relationship could not be changed because one or more of the foreign-key properties is non-nullable在保存时得到.
我相信这就是发生的事情: 由于一个或多个外键属性不可为空,因此无法更改关系
这让我回到原点,因为在我的场景中,我不能只从数据库中获取并更新条目和调用SaveChanges.
Ger*_*old 11
因为EF无法检测导航属性中的更改
这似乎是一个有点扭曲的描述,_dbContext.Entry(obj).State = EntityState.Modified不会将navigaton属性标记为已修改.
当然EF跟踪导航属性的变化.它跟踪附加到上下文的所有实体的属性和关联的更改.因此,你的问题的答案现在已经明确表示......
是否可以在EF中更新EF中的子集合
......是:是的.
唯一的事情是:你不要开箱即用.
更新任何实体的"开箱即用"方式,无论是父项还是某个集合中的子项,都是:
SaveChanges().就这样.如果跟踪更改,您永远不会State明确设置实体.
但是,在断开连接(n层)的情况下,这会变得更加复杂.我们序列化和反序列化实体,因此不能有任何跟踪其更改的上下文.如果我们想将实体存储在数据库中,那么现在我们的任务就是让EF知道这些变化.基本上有两种方法可以做到这一点:
在谈到协会时,我们总是要画国家.我们必须从数据库中获取当前实体,并确定添加/删除了哪些子项.没有办法从反序列化的对象图本身推断出这一点.
有各种方法来缓解这种无聊和精心绘制国家的任务,但这超出了本问答的范围.一些参考:
因为你这样做很奇怪。
这需要延迟加载来获取子项(显然可以根据您的使用情况进行修改)
//获取父级
var parent = context.Parent.Where(x => x.Id == parentId).SingleOrDefault();
Run Code Online (Sandbox Code Playgroud)
给你写了完整的测试方法。(适用于您的情况)
EmailMessage(parent) 是父级,它没有或有多个 EmailAttachment's(child's)
[TestMethod]
public void TestMethodParentChild()
{
using (var context = new MyContext())
{
//put some data in the Db which is linked
//---------------------------------
var emailMessage = new EmailMessage
{
FromEmailAddress = "sss",
Message = "test",
Content = "hiehdue",
ReceivedDateTime = DateTime.Now,
CreateOn = DateTime.Now
};
var emailAttachment = new EmailAttachment
{
EmailMessageId = 123,
OrginalFileName = "samefilename",
ContentLength = 3,
File = new byte[123]
};
emailMessage.EmailAttachments.Add(emailAttachment);
context.EmailMessages.Add(emailMessage);
context.SaveChanges();
//---------------------------------
var firstEmail = context.EmailMessages.FirstOrDefault(x => x.Content == "hiehdue");
if (firstEmail != null)
{
//change the parent if you want
//foreach child change if you want
foreach (var item in firstEmail.EmailAttachments)
{
item.OrginalFileName = "I am the shit";
}
}
context.SaveChanges();
}
}
Run Code Online (Sandbox Code Playgroud)
更新
做你的 AutoMappper 的东西......正如你在评论中所说的那样。
然后,当您准备保存并将其恢复为正确的类型时,即一次代表实体(Db),然后执行此操作。
var modelParent= "Some auto mapper magic to get back to Db types."
var parent = context.Parent.FirstOrDefault(x => x.Id == modelParent.Id);
//use automapper here to update the parent again
if (parent != null)
{
parent.Childs = modelParent.Childs;
}
//this will update all childs ie if its not in the new list from the return
//it will automatically be deleted, if its new it will be added and if it
// exists it will be updated.
context.SaveChanges();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9921 次 |
| 最近记录: |