我正在通过将现有实体附加到我的数据上下文来更新它:
var updatedDocumentState = new AccDocumentState()
{
Id = accDocumentState.Id,
IsDocumentary = accDocumentState.IsDocumentary,
IsEditable = accDocumentState.IsEditable,
IsRecursive = accDocumentState.IsRecursive,
Title = accDocumentState.Title,
Reportable = accDocumentState.Reportable,
};
context.AccDocumentStates.Attach(updatedDocumentState);
context.ObjectStateManager.ChangeObjectState(updatedDocumentState, System.Data.EntityState.Modified);
flag = context.SaveChanges() > 0;
这样可行,但是在保存附加实体之后,我没有更新的现有实体的属性,但是我想保持原样,被覆盖并给出空值。如何附加我的实体并保留我尚未更新的现有实体的属性?
答案 0 :(得分:1)
根据msdn 当您将实体对象条目的EntityState更改为Modified时,无论当前值或原始值如何,对象的所有属性都将标记为已修改。 http://msdn.microsoft.com/en-us/library/system.data.objects.objectstatemanager.changeobjectstate.aspx
因此,我认为所有其他属性都设置为null,因为您创建的对象将具有其他属性为null或其默认值。 以下是修改后的代码。
var updatedDocumentState = context.AccDocumentStates.First(a => a.Id== accDocumentState.Id);
updatedDocumentState.IsDocumentary = accDocumentState.IsDocumentary,
updatedDocumentState.IsEditable = accDocumentState.IsEditable,
updatedDocumentState.IsRecursive = accDocumentState.IsRecursive,
updatedDocumentState.Title = accDocumentState.Title,
updatedDocumentState.Reportable = accDocumentState.Reportable,
flag = context.SaveChanges() > 0;
答案 1 :(得分:1)
EF有一个对象数据更改跟踪器。通过代理启用 Tracking changes in Poco entries
基本上你/找到首先阅读对象/ Poco实体。 仅更改所需的属性。并保存。 仅更新已更改的属性。
如果您没有使用autoDetectChnages
this.Configuration.AutoDetectChangesEnabled = false; ////<<<<<<<<< Default true
然后你会在保存之前调用检测更改。
但无论哪种方式,这个概念都是基于Read first to get实体。 进行必要的更改并保存。
仅将实际更改发送回Db。 例如:
var mypoco = Context.Set<TPoco>.Find(1);
myPoco.propertyXyz = "changed";
// normally not required by default, But incase your are not using tracking proxies , tell ef heads Up
// Context.Context.ChangeTracker.DetectChanges(); // uncomment when needed
Context.SaveChanged();
仅将实际更改发送到DB。
虽然来自Rameez的POST是正确的,但它没有说明为什么将整个条目设置为已更改是可取的,也不是为什么这样做?为什么要从文档中链接State条目?
Context.Entry(poco).State = state; // why do this ? or the objectContext equivalent
这将导致在SaveChanges上转到Database的所有值的UPdate Set 由于所有字段都将被视为已更改。这不是使用EF的好方法。
了解EF中的自动检测更改非常重要。 见Automatic detect changes 和Entity states and SaveChanges
答案 2 :(得分:1)
作为解决问题的方法,只为要更新的字段创建模型。假设这是一个常见的场景,并保证额外的模型,以避免额外调用数据库。
使用新的最小化模型,指向同一个表,但只有所需的属性,它将按您的意愿工作。当然,EF方面没有任何改变,但它只会更新它所知道的属性。
虽然我同意这不是EF的设计方式,但我也对额外的数据库调用感到沮丧,无法进行更新或删除。这个解决方案有助于此。
答案 3 :(得分:0)
试试这个。也许你需要的是:
var updatedDocumentState = context.AccDocumentStates.Find(accDocumentState.Id)
{
IsDocumentary = accDocumentState.IsDocumentary,
IsEditable = accDocumentState.IsEditable,
IsRecursive = accDocumentState.IsRecursive,
Title = accDocumentState.Title,
Reportable = accDocumentState.Reportable,
};
flag = context.SaveChanges() > 0;
答案 4 :(得分:0)
我对以下内容感到满意。首先,我创建了一个扩展方法,为我想要限制更新的属性集中的任何属性取消设置IsModified标志:
public static void RestrictModifiedProps<ENT>(this DbContext context, ENT entity, IEnumerable<string> restrictedPropNames)
where ENT : class
{
//Grab the meta entry that knows whether the entity/properties have been updated
var entry = context.Entry(entity);
if (entry == null) return;
//loop over properties, only allow properties in the
// restrictedPropNames list to be modified
foreach (var propName in entry.CurrentValues.PropertyNames)
{
var prop = entry.Property(propName);
if (!prop.IsModified) continue;
prop.IsModified = restrictedPropNames.Any(O => O == propName);
}
}
就我而言,我接受实体的属性值从json帖子到MVC动作。所以,我想知道发布了哪些属性并为控制器创建(耦合)扩展方法:
public static JObject JsonPostData(this Controller cntrlr)
{
//ensure we're at the start of the input stream
Stream req = cntrlr.Request.InputStream;
req.Seek(0, SeekOrigin.Begin);
//read in any potential json
string json = d2s.SafeTrim(new StreamReader(req).ReadToEnd());
if (string.IsNullOrWhiteSpace(json)
|| !json.StartsWith("{")
|| !json.EndsWith("}"))
return null;
//try to deserialize it
return JsonConvert.DeserializeObject(json) as JObject;
}
public static IEnumerable<JProperty> JsonPostProperties(this Controller cntrlr)
{
JObject jObj = cntrlr.JsonPostData();
if (jObj == null) return null;
return jObj.Properties();
}
public static IEnumerable<string> JsonPostPropNames(this Controller cntrlr)
{
IEnumerable<JProperty> jProps = cntrlr.JsonPostProperties();
if (jProps == null) return null;
return jProps.Select(O => O.Name);
}
在行动中,我们得到:
[HttpPost, ActionName("Edit")]
public virtual ActionResult Edit_Post(ENT obj)
{
...code...
Ctxt.Set<ENT>().Attach(obj);
Ctxt.Entry(obj).State = EntityState.Modified;
Ctxt.RestrictModifiedProps(obj, this.JsonPostPropNames());
...code...
}
答案 5 :(得分:0)
如果您只是要排除一个或两个属性,比如说您从不希望允许更新Title属性(在您的示例中),只需在之后在目标属性上取消设置IsModified即可设置对象状态修改:
context.AccDocumentStates.Attach(updatedDocumentState);
context.ObjectStateManager.ChangeObjectState(updatedDocumentState, System.Data.EntityState.Modified);
context.Entry(updatedDocumentState).Property("Title").IsModified = false;
flag = context.SaveChanges() > 0;
另外FYI - VS中的默认MVC5项目使用此行来设置对象的修改属性:
context.Entry(updatedDocumentState).State = System.Data.EntityState.Modified;