我需要设置一个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
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不包含引用“Sample.Models.Department”类型对象的ObjectStateEntry。
这两个EntityKeys是相等的。为什么第二个代码块会失败?我怎么才能修好它?
发布于 2009-05-22 15:06:43
第二个代码块失败的原因是因为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列的任何内容。调用该方法的唯一有趣部分是,您需要告诉它如何通过委托找到键属性,作为扩展方法的第二个参数:
[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);
}
}由于扩展方法正在调用AcceptAllChanges,如果您同时对多个实体进行更新,则需要小心调用它--如果您不小心,则很容易“丢失”更新。因此,这种方法只适用于简单的更新场景--例如,许多MVC操作方法:)
发布于 2009-11-26 10:42:45
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;
T newEntity = Activator.CreateInstance<T>();
newEntity.EntityKey = db.CreateEntityKey(entitySetName, entity);
Type t = typeof(T);
foreach(EntityKeyMember keyMember in newEntity.EntityKey.EntityKeyValues) {
PropertyInfo p = t.GetProperty(keyMember.Key);
p.SetValue(newEntity, keyMember.Value, null);
}
db.Attach(newEntity);
//db.AcceptAllChanges();
db.ApplyPropertyChanges(entitySetName, entity);
}
}发布于 2010-07-29 07:31:48
试着使用下面的代码,并让我知道它是否适合你。
[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
}
}
} https://stackoverflow.com/questions/898260
复制相似问题