C# EntityKey和ApplyPropertyChanges()
我需要设置EntityObject的EntityKey。我知道它的类型和id值。我不想不必要地查询数据库 这很有效C# EntityKey和ApplyPropertyChanges(),c#,.net,asp.net-mvc,entity-framework,C#,.net,Asp.net Mvc,Entity Framework,我需要设置EntityObject的EntityKey。我知道它的类型和id值。我不想不必要地查询数据库 这很有效 // // POST: /Department/Edit/5 [AcceptVerbs(HttpVerbs.Post)] public ActionResult Edit(Guid id, Department Model) { Model.EntityKey = (from Department d in db.Department
//
// POST: /Department/Edit/5
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, Department Model)
{
Model.EntityKey = (from Department d in db.Department
where d.Id == id
select d).FirstOrDefault().EntityKey;
db.ApplyPropertyChanges(Model.EntityKey.EntitySetName, Model);
db.SaveChanges();
return RedirectToAction("Index");
}
这失败了
//
// POST: /Department/Edit/5
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, Department Model)
{
String EntitySetName = db.DefaultContainerName + "." + Model.GetType().Name;
Model.EntityKey = new System.Data.EntityKey(EntitySetName, "Id", Model.Id);
db.ApplyPropertyChanges(Model.EntityKey.EntitySetName, Model);
db.SaveChanges();
return RedirectToAction("Index");
}
ApplyPropertyChanges()行失败,出现以下异常:
ObjectStateManager不支持
包含带有
对类型为的对象的引用
“样本、模型、部门”
这两个实体键相等。为什么第二块代码会失败?如何修复它?您的第二个代码块失败的原因是EF在ObjectStateManager中找不到对象-也就是说,当它从db中提取对象时,它会将它们放在状态管理器中以便跟踪它们-这与模式类似。尽管有EntityKey,但对象不在状态管理器中,因此EF无法持久化更改。你可以通过自己将对象放入状态管理器来绕过这个问题,但你对此有点偷偷摸摸 这项工作:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, Department model)
{
var entitySetName = db.DefaultContainerName + "." + model.GetType().Name;
var entityKey = new System.Data.EntityKey(entitySetName, "Id", model.Id);
db.Attach(new Department{Id = id, EntityKey = entityKey});
db.AcceptAllChanges();
db.ApplyPropertyChanges(entitySetName, model);
db.SaveChanges();
}
。。。但是它不是很干净。基本上,这是用一个实体键附加一个“空”对象,接受所有更改,然后用实际更新的值调用ApplyPropertyChanges
在扩展方法中也包含同样的内容-这应该适用于任何使用单个db列作为主键的情况。调用该方法唯一有趣的部分是,您需要告诉它如何通过委托(作为扩展方法的第二个参数)找到key属性:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, Department model)
{
db.ApplyDetachedPropertyChanges(model, x => x.Id);
db.SaveChanges();
}
public static class EfExtensions
{
public static void ApplyDetachedPropertyChanges<T>(this ObjectContext db, T entity, Func<T, int> getIdDelegate)
where T : EntityObject
{
var entitySetName = db.DefaultContainerName + "." + entity.GetType().Name;
var id = getIdDelegate(entity);
var entityKey = new EntityKey(entitySetName, "Id", id);
db.Attach(new Department {Id = id, EntityKey = entityKey});
db.AcceptAllChanges();
db.ApplyPropertyChanges(entitySetName, entity);
}
}
以及扩展方法:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, Department model)
{
db.ApplyDetachedPropertyChanges(model, x => x.Id);
db.SaveChanges();
}
public static class EfExtensions
{
public static void ApplyDetachedPropertyChanges<T>(this ObjectContext db, T entity, Func<T, int> getIdDelegate)
where T : EntityObject
{
var entitySetName = db.DefaultContainerName + "." + entity.GetType().Name;
var id = getIdDelegate(entity);
var entityKey = new EntityKey(entitySetName, "Id", id);
db.Attach(new Department {Id = id, EntityKey = entityKey});
db.AcceptAllChanges();
db.ApplyPropertyChanges(entitySetName, entity);
}
}
公共静态类扩展
{
公共静态void ApplyDetailedPropertyChanges(此ObjectContext数据库、T实体、Func getIdDelegate)
其中T:EntityObject
{
var entitySetName=db.DefaultContainerName+“+entity.GetType().Name;
var id=getIdDelegate(实体);
var entityKey=新的entityKey(entitySetName,“Id”,Id);
附加(新部门{Id=Id,EntityKey=EntityKey});
db.acceptablechanges();
db.ApplyPropertyChanges(entitySetName,entity);
}
}
由于扩展方法正在调用AcceptAllChanges,如果您同时对多个实体进行更新,则需要小心调用此方法-如果不小心,很容易“丢失”更新。因此,这种方法只适用于简单的更新场景-例如,许多MVC操作方法:)公共静态类扩展
{
公共静态void ApplyDetailedPropertyChanges(此ObjectContext数据库、T实体、Func getIdDelegate)
其中T:EntityObject
{
var entitySetName=db.DefaultContainerName+“+entity.GetType().Name;
T newEntity=Activator.CreateInstance();
newEntity.EntityKey=db.CreateEntityKey(entitySetName,entity);
类型t=类型(t);
foreach(newEntity.EntityKey.EntityKeyValues中的EntityKeyMember-keyMember){
PropertyInfo p=t.GetProperty(keyMember.Key);
p、 SetValue(newEntity,keyMember.Value,null);
}
db.附件(新实体);
//db.acceptablechanges();
db.ApplyPropertyChanges(entitySetName,entity);
}
}
尝试使用下面的代码,并让我知道它是否适合您
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Guid id, Department Model)
{
using (var context = new EntityContext())
{
try
{
Object entity = null;
IEnumerable<KeyValuePair<string, object>> entityKeyValues =
new KeyValuePair<string, object>[] {
new KeyValuePair<string, object>("DepartmentID", id) };
// Create the key for a specific SalesOrderHeader object.
EntityKey key = new EntityKey("EntityContext.Deparment",
entityKeyValues);
// Get the object from the context or the persisted store by its key.
if (context.TryGetObjectByKey(key, out entity))
{
context.ApplyPropertyChanges(key.EntitySetName, Model);
context.SaveChanges();
}
else
{
// log message if we need
//"An object with this key could not be found."
}
}
catch (EntitySqlException ex)
{
// log message
}
}
}
[AcceptVerbs(HttpVerbs.Post)]
公共操作结果编辑(Guid id,部门模型)
{
使用(var context=new EntityContext())
{
尝试
{
对象实体=null;
IEnumerable entityKeyValues=
新的KeyValuePair[]{
新的KeyValuePair(“部门id”,id)};
//为特定SalesOrderHeader对象创建密钥。
EntityKey=new EntityKey(“EntityContext.Deparment”,
entityKeyValues);
//通过其键从上下文或持久化存储中获取对象。
if(context.TryGetObjectByKey(key,out实体))
{
ApplyPropertyChanges(key.EntitySetName,Model);
SaveChanges();
}
其他的
{
//如果需要,记录消息
//“找不到具有此键的对象。”
}
}
捕获(EntitySqlException ex)
{
//日志消息
}
}
}
当它在其他页面上工作时,我也遇到了同样的问题。我不知道这个评论是否有用。。。但我最终发现,在我的objet(相当于您的部门)中,我的“Id”没有出现在表单中
仅仅是在我的表单上添加它(虽然我已经删除了它…)就解决了我的问题。(使用style=“visibility:hidden”,为了不看到他…改进Steve Willcock的伟大实现,下面是我的建议 它比原始示例更多地使用反射(.NET的一部分)来为您节省一些代码。它还自动支持任何类型的实体类,而不仅仅是“部门” 此外,它摆脱了过时的
ApplyPropertyChanges
方法,并使用了新的ApplyCurrentValues
方法
方法
该方法基本上只是使用反射来动态地获取“Id”属性的值,并对其进行设置。这样就省去了与代理之间的所有麻烦
public static void ApplyDetachedPropertyChanges<T>(this ObjectContext db, T entity) where T : EntityObject
{
PropertyInfo idProperty = typeof(T).GetProperty("Id");
var entitySetName = db.DefaultContainerName + "." + entity.GetType().Name;
var id = idProperty.GetValue(entity, null);
var entityKey = new EntityKey(entitySetName, "Id", id);
Type type = entity.GetType();
EntityObject obj = (EntityObject)Activator.CreateInstance(type);
idProperty.SetValue(obj, id, null);
obj.EntityKey = entityKey;
db.Attach(obj);
db.AcceptAllChanges();
db.ApplyCurrentValues(entitySetName, entity);
}
+1为扩展方法。真漂亮!=)如果表使用多列PK,该方法必须如何更改?您需要对扩展方法进行重载,该方法使用KeyValuePair的IEnumerable指定键,然后在EntityKey上调用相应的构造函数重载。为了维护stype的安全性并避免在KeyValuePair中传递字符串,您可以传递一组“key finding”委托以及要放入键中的值。基于这个伟大的答案,我对它进行了一些改进,并利用它制作了我自己的小方法,我也将其作为答案发布。它适用于任何类型的实体对象,并且