3

我通过将现有实体附加到我的数据上下文来更新它,如下所示:

    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;

这有效,但是在保存附加实体后,我没有更新但我想保持原样的现有实体的属性被覆盖并赋予空值。如何附加我的实体并保留我尚未更新的现有实体的属性?

4

6 回答 6

1

根据 msdn,当您将实体对象条目的 EntityState 更改为已修改时,该对象的所有属性都被标记为已修改,无论当前值或原始值如何。 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;
于 2013-07-28T09:46:49.693 回答
1

EF 有一个对象数据更改跟踪器。通过代理启用 跟踪 Poco 条目中的更改

本质上,你/find 首先阅读 Object/Poco 实体。仅更改您想要的那些属性。并保存。仅更新更改的属性。

如果您没有使用 autoDetectChnages

 this.Configuration.AutoDetectChangesEnabled = false; ////<<<<<<<<< Default true

然后你会在保存之前调用检测更改。

但无论哪种方式,这个概念都是基于先读取以获取实体。进行必要的更改并保存。

仅将实际更改发送回 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 是正确的,但它并没有说明为什么将整个条目设置为已更改是可取的,也没有说明为什么要这样做?为什么要从文档中链接状态条目?

   Context.Entry(poco).State = state;  // why do this ? or the objectContext equivalent 

这将导致所有值在 SaveChanges 上进入数据库的更新集,因为所有字段都将被视为已更改。这不是使用 EF 的好方法。

了解 EF 中的自动检测变化很重要。请参阅自动检测更改实体状态和 SaveChanges

于 2013-07-28T13:41:22.163 回答
1

作为您的问题的解决方法,为您正在更新的字段创建一个模型。假设这是一个常见的场景,并保证额外的模型避免额外调用 db。

使用新的最小化模型,指向同一个表,但只有所需的属性,它将按您的意愿工作。当然,EF 端没有任何变化,但它只会更新它知道的属性。

虽然我同意这不是 EF 的设计方式,但我也对执行更新或删除的额外数据库调用感到沮丧。该解决方案对此有所帮助。

于 2013-07-28T13:52:14.117 回答
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;
于 2013-07-30T05:50:28.053 回答
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;

另外仅供参考 - VS 中的默认 MVC5 项目使用此行来设置对象的修改属性:

context.Entry(updatedDocumentState).State = System.Data.EntityState.Modified;
于 2014-10-27T21:13:41.067 回答
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...

}
于 2014-02-10T21:15:18.917 回答