我的存储库中有一个通用方法,用于更新edmx模型中所有对象的公共属性:
private void SetUpdateParams(TEntity entity)
{
PropertyInfo prop = typeof(TEntity).GetProperty("CommonProperty");
prop.SetValue(entity, "Some Value", null);
}
此属性由add,update和delete方法调用。例如:
public void Delete(TEntity entity)
{
SetUpdateParams(entity);
_objectSet.DeleteObject(entity);
txDB.SaveChanges();
}
这一切都非常好用,直到我尝试将子项包含在级联删除场景中。由于我必须使用的sprocs要求设置此特定属性,我现在必须通过关系递归并在ObjectSet中的任何已加载子项上设置此属性。问题是我似乎无法找到任何方法来做到这一点。有没有人以前做过这样的事情?
答案 0 :(得分:1)
这不是最简单的解决方案,可能有点乏味,但我通过跨越对象图,在我找到它时更新属性,并跟踪我的内容来实现您在我的项目中所需的内容参观。它为本科计算机科学课提供了很好的回忆。 =)
基本上,获取您的对象,获取其属性,并将它们推送到堆栈上。对于堆栈中的每个属性,请测试它是否是您要查找的属性。处理如果匹配,则忽略简单数据类型,如果是复杂对象则添加到堆栈。
在我的实施中帮助我的一些事情:
ObjectContext
)自定义Save()方法。我打电话给这个修正,然后拨打base.SaveChanges()
。就像我说的,这不是一个简单直接的问题,但我的代码处理深层对象图并更新多个属性实例。如果有兴趣,我可以跟进一些伪代码。
修改/更新强>
如代码所示,我有兴趣更新可能出现在图表中的任意数量对象的当前UserName和DateTime值。
备注:强>
IInsertedInfo
包含我们需要更新的属性。因此,如果对象实现IInsertedInfo
,我们就知道要更新其属性。IRequiresCurrentUserDateTime
的对象是在其图形中的某个位置具有实现IInsertedInfo
的对象的对象。ObjectStateManager
。我并不认为这是最简洁的解决方案,但它对我来说很好。此外,检查IRequiresCurrentUserDateTime
和其他过滤器(为清楚起见省略了一些过滤器)仅用于保持搜索空间的可管理性,并避免跨越.NET对象,非类类型等。
private void HandleInsertedUserNames(string userName)
{
// grab any entity that requires a current user value
var requiresUser = this.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified)
.Where(ose => ose.Entity is IRequiresCurrentUserDateTime
|| ose.Entity is IInsertedInfo)
.Select(ose => ose.Entity);
var now = DateTime.Now;
object current;
var seen = new HashSet<object>();
var stack = new Stack<object>();
// for each entity requiring a current user value...
foreach (var obj in requiresUser)
{
// traverse its object graph and update any objects that implement IRequiresCurrentUserDateTime
stack.Push(obj);
while (stack.Count > 0)
{
current = stack.Pop();
if (current != null && !seen.Contains(current))
{
// mark object as seen
seen.Add(current);
// if object implements IInsertedInfo, then set its property
if (current is IInsertedInfo)
{
(current as IInsertedInfo).UserName = userName;
(current as IInsertedInfo).DateTime = now;
// we can continue on to the next object in the stack if we've hit an IInsertedInfo
continue;
}
// REMOVED FILTERING TESTS I USED TO REDUCE SEARCH SPACE (e.g.: is modified?)
if (current is IRequiresCurrentUserDateTime)
{
// push any instance, public properties and push them to the stack
current.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)
// HERE YOU CAN FILTER THE PROPERTY COLLECTION VIA WHERE CLAUSES (e.g.: only certain namespace, type, etc)
// select the actual value of the property
.Select(type => type.GetValue(current, null))
// further filter -- only values NOT already in the requiresUser
// list and those that implement IRequiresCurrentUserDateTime or IInsertedInfo
.Where(value => !requiresUser.Contains(value)
&& (value is IRequiresCurrentUserDateTime
|| value is IInsertedInfo))
.ToList().ForEach(stack.push);
}
}
}
}
}