entity framework 中的递归实体分离
Recursive entity detaching in entity framework
我写了一个方法来递归地分离我在 entity framework 中的对象。实际上它是有效的,但问题是,执行此方法后,一对多属性(对象的集合)被删除。在我的代码下方:
public void DetachRec(object objectToDetach)
{
DetachRec(objectToDetach, new HashSet<object>());
}
// context is my ObjectContext
private void DetachRec(object objectToDetach, HashSet<object> visitedObjects)
{
visitedObjects.Add(objectToDetach);
if (objectToDetach == null)
{
return;
}
Type type = objectToDetach.GetType();
PropertyInfo[] propertyInfos = type.GetProperties();
foreach (PropertyInfo propertyInfo in propertyInfos)
{
// on to many
if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>))
{
if (context.Entry(objectToDetach).Collection(propertyInfo.Name).IsLoaded)
{
var propValue = (IEnumerable) propertyInfo.GetValue(objectToDetach, null);
if (propValue != null)
{
var subcontext = new List<object>();
foreach (var subObject in propValue)
{
subcontext.Add(subObject);
}
foreach (var subObject in subcontext)
{
if (!visitedObjects.Contains(subObject))
{
context.DetachRecursive(subObject, visitedObjects);
}
}
}
}
}
// (many to one)
else if (propertyInfo.PropertyType.Assembly == type.Assembly)
{
//the part to detach many-to-one objects
}
}
context.Detach(objectToDetach);
}
在分离集合元素之前,您可以存储集合值并将集合 属性 设置为 null
。这样,当元素 and/or 父实体分离时,您将阻止 EF 删除集合元素。在此过程结束时,您只需恢复这些值即可。
首先将以下 using
添加到源代码文件中:
using System.Data.Entity.Infrastructure;
改变public方法实现如下:
public void DetachRec(object objectToDetach)
{
var visitedObjects = new HashSet<object>();
var collectionsToRestore = new List<Tuple<DbCollectionEntry, object>>();
DetachRec(objectToDetach, visitedObjects, collectionsToRestore);
foreach (var item in collectionsToRestore)
item.Item1.CurrentValue = item.Item2;
}
私有递归方法签名为:
private void DetachRec(object objectToDetach, HashSet<object> visitedObjects, List<DbCollectionEntry, object>> collectionsToRestore)
和一对多 if
块体到:
var collectionEntry = context.Entry(objectToDetach).Collection(propertyInfo.Name);
if (collectionEntry.IsLoaded)
{
var collection = collectionEntry.CurrentValue;
if (collection != null)
{
collectionsToRestore.Add(Tuple.Create(collectionEntry, collection));
collectionEntry.CurrentValue = null;
foreach (var item in (IEnumerable)collection)
{
if (!visitedObjects.Contains(item))
{
DetachRec(item, visitedObjects, collectionsToRestore);
}
}
}
}
大功告成。
我写了一个方法来递归地分离我在 entity framework 中的对象。实际上它是有效的,但问题是,执行此方法后,一对多属性(对象的集合)被删除。在我的代码下方:
public void DetachRec(object objectToDetach)
{
DetachRec(objectToDetach, new HashSet<object>());
}
// context is my ObjectContext
private void DetachRec(object objectToDetach, HashSet<object> visitedObjects)
{
visitedObjects.Add(objectToDetach);
if (objectToDetach == null)
{
return;
}
Type type = objectToDetach.GetType();
PropertyInfo[] propertyInfos = type.GetProperties();
foreach (PropertyInfo propertyInfo in propertyInfos)
{
// on to many
if (propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>))
{
if (context.Entry(objectToDetach).Collection(propertyInfo.Name).IsLoaded)
{
var propValue = (IEnumerable) propertyInfo.GetValue(objectToDetach, null);
if (propValue != null)
{
var subcontext = new List<object>();
foreach (var subObject in propValue)
{
subcontext.Add(subObject);
}
foreach (var subObject in subcontext)
{
if (!visitedObjects.Contains(subObject))
{
context.DetachRecursive(subObject, visitedObjects);
}
}
}
}
}
// (many to one)
else if (propertyInfo.PropertyType.Assembly == type.Assembly)
{
//the part to detach many-to-one objects
}
}
context.Detach(objectToDetach);
}
在分离集合元素之前,您可以存储集合值并将集合 属性 设置为 null
。这样,当元素 and/or 父实体分离时,您将阻止 EF 删除集合元素。在此过程结束时,您只需恢复这些值即可。
首先将以下 using
添加到源代码文件中:
using System.Data.Entity.Infrastructure;
改变public方法实现如下:
public void DetachRec(object objectToDetach)
{
var visitedObjects = new HashSet<object>();
var collectionsToRestore = new List<Tuple<DbCollectionEntry, object>>();
DetachRec(objectToDetach, visitedObjects, collectionsToRestore);
foreach (var item in collectionsToRestore)
item.Item1.CurrentValue = item.Item2;
}
私有递归方法签名为:
private void DetachRec(object objectToDetach, HashSet<object> visitedObjects, List<DbCollectionEntry, object>> collectionsToRestore)
和一对多 if
块体到:
var collectionEntry = context.Entry(objectToDetach).Collection(propertyInfo.Name);
if (collectionEntry.IsLoaded)
{
var collection = collectionEntry.CurrentValue;
if (collection != null)
{
collectionsToRestore.Add(Tuple.Create(collectionEntry, collection));
collectionEntry.CurrentValue = null;
foreach (var item in (IEnumerable)collection)
{
if (!visitedObjects.Contains(item))
{
DetachRec(item, visitedObjects, collectionsToRestore);
}
}
}
}
大功告成。