更新 EF 中的实体属性,其中属性是另一个实体

Posted

技术标签:

【中文标题】更新 EF 中的实体属性,其中属性是另一个实体【英文标题】:Update Entity property in EF where property is another entity 【发布时间】:2014-12-03 16:32:13 【问题描述】:

我正在使用 Entity Framework 6,我需要更新实体的属性。

我有以下实体:

public class File 

  public Int32 Id  get; set; 
  public Byte Data  get; set; 
  public DateTime Updated  get; set; 
  public virtual Mime Mime  get; set; 

public class Mime 

  public Int32 Id  get; set; 
  public String Name  get; set; 
  public virtual ICollection<File> Files  get; set; 

然后我使用了以下内容:

_repository.Update<File>(file, x => x.Data, x => x.Mime, x => x.Updated);

仓库方法如下:

public void Update<T>(T entity,
                      params Expression<Func<T, Object>>[] properties)
                      where T : class 


  _context.Set<T>().Attach(entity);

  foreach (var property in properties) 
  
    MemberExpression expression =
                     property.Body is MemberExpression ? 
                     (MemberExpression)property.Body : 
                     (MemberExpression)(((UnaryExpression)property.Body)
                                                                  .Operand);
    _context.Entry<T>(entity)
            .Property(expression.Member.Name).IsModified = true;
  

这适用于Data 和更新的属性,但不适用于Mime。我得到了错误:

类型“文件”的属性“Mime”不是原始或复杂属性。 Property 方法只能用于原始或复杂属性。使用引用或集合方法。

是否有可能完成这项工作并将其集成到我的存储库方法中?

【问题讨论】:

第一个问题是:你为什么有这种精心设计的Update 方法?为什么不能将其留给 EF 的更改跟踪器以将属性标记为已修改?更大的图景是什么? File 实体有一个属性 Data 可能有点大,因为它包含一个文件......所以我想更新一些字段而不将数据加载到内存中。这有意义吗?当我没有与之相关的实体时,这很有效。 你应该看看table spliting 是的,我已拆分表...这是文件表,我要更新文件。 【参考方案1】:

是的,我认为可以做到。这里的问题是我没有看到任何简单的方法来检查何时属性是表的一部分,或者它是导航属性。因此很难调用正确的行为。

如果您有兴趣,请查看 EF6 源代码,InternalEntityEntry.cs -> Property(..) 通过元数据进行大量属性验证。

主要思想是基本上扫描您的概念模型,并确定该属性何时是导航属性(例如该属性是否指向另一个表),或者它是否复杂/原始。

据此,您调用了正确的功能。

var propertyName = expression.Member.Name;                                              
var propertyType = __get_property_type__(propertyName);

if(propertyType==Property || propertyType==Complex)

    _context.Entry<T>(entity)
        .Property(propertyName).IsModified = true;

    continue;


if(propertyType==Navigational)

    // hm, do we need Attach it first?!
    // not sure.. have to test first.
    dynamic underlyingReference = entity.GetType()
            .GetProperty(propertyName)
            .GetValue(entity, null);

    _context.Entry(underlyingReference).State = EntityState.Modified;

这里的问题是让__get_property_type__ 有效。 Microsoft.Data.Edm.dll 可以让您使用概念模型,但我认为这并不容易。

这是 EF6 检测我们是否正在处理引用属性的方式:

EdmMember member;
EdmEntityType.Members.TryGetValue(propertyName, false, out member);

var asNavProperty = member as NavigationProperty;
// if asNavProperty!=null, we have navigation property.

【讨论】:

【参考方案2】:

100% 格茨点。我认为没有理由以他们的方式解决问题。 无论如何,回答这个问题。你有另一个答案。可能有用。

缺少的是这个:

如何从上下文中获取托管类型的列表。

    public static  IList<Type> GetContextManagedTypes(DbContext context) 
        ObjectContext objContext = ((IObjectContextAdapter)context).ObjectContext;
        MetadataWorkspace workspace = objContext.MetadataWorkspace;
        IEnumerable<EntityType> managedTypes = workspace.GetItems<EntityType>(DataSpace.OSpace);

        var typeList = new List<Type>();
        foreach (var managedType in managedTypes) 
            var pocoType = managedType.FullName.GetCoreType();
            typeList.Add(pocoType);
        

        return typeList;
    

【讨论】:

以上是关于更新 EF 中的实体属性,其中属性是另一个实体的主要内容,如果未能解决你的问题,请参考以下文章

无法更新标识列“索引”。 EF核心

EF Core中怎么实现自动更新实体的属性值到数据库

EF中更新操作 ID自增但不是主键 ;根据ViewModel更新实体的部分属性

EF-实体更新

EFCore:简单属性更新期间的实体关联错误

使用 EF Core 保存附加实体时如何删除子实体