【问题标题】:Entity Framework Code First and Entity tracking实体框架代码优先和实体跟踪
【发布时间】:2012-12-17 15:02:52
【问题描述】:

假设您有一个纯 POCO 对象(例如Customer),您在业务层中创建了该对象,然后调用了context.Add(customer)。您传入并引用的 Customer 对象是否会被更改跟踪?换句话说:您传入的对象是ObjectStateManager 正在跟踪的同一对象还是不同的对象?

如果它们不是同一个对象,那不会导致大量内存消耗,因为一直维护着两个对象图:一个由您(开发人员)在业务层维护,另一个由 @987654326 @ 在 DAL 中?

【问题讨论】:

标签: c# .net entity-framework ef-code-first


【解决方案1】:

上下文的想法是不要让它变得太大。甚至拥有具有不同数据视图的多个上下文。甚至可以为每个工作单元使用新的上下文。 所以是的,它可以变大。关于这个主题的一些好读物 搜索有界上下文和 Luw 模式。例如来自 Julie Lerman。

这是由 EF 管理的反编译 IEntityWrapper(来自 EF5.0 / Net 4.0) 将实体放入 ObjectContext 时使用 IENtityWrapper。

我让你决定它是否大。
正如 Millimetric 提到的,参考文献是 object Entity { get; } // see below inside wrapper

internal interface IEntityWrapper
{
void EnsureCollectionNotNull(RelatedEnd relatedEnd);
EntityKey GetEntityKeyFromEntity();
void AttachContext(ObjectContext context, EntitySet entitySet, MergeOption mergeOption);
void ResetContext(ObjectContext context, EntitySet entitySet, MergeOption mergeOption);
void DetachContext();
void SetChangeTracker(IEntityChangeTracker changeTracker);
void TakeSnapshot(EntityEntry entry);
void TakeSnapshotOfRelationships(EntityEntry entry);
void CollectionAdd(RelatedEnd relatedEnd, object value);
bool CollectionRemove(RelatedEnd relatedEnd, object value);
object GetNavigationPropertyValue(RelatedEnd relatedEnd);
void SetNavigationPropertyValue(RelatedEnd relatedEnd, object value);
void RemoveNavigationPropertyValue(RelatedEnd relatedEnd, object value);
void SetCurrentValue(EntityEntry entry, StateManagerMemberMetadata member, int ordinal, object target, object value);
void UpdateCurrentValueRecord(object value, EntityEntry entry);
RelationshipManager RelationshipManager { get; }
bool OwnsRelationshipManager { get; }
object Entity { get; }
EntityEntry ObjectStateEntry { get; set; }
EntityKey EntityKey { get; set; }
ObjectContext Context { get; set; }
MergeOption MergeOption { get; }
Type IdentityType { get; }
bool InitializingProxyRelatedEnds { get; set; }
bool RequiresRelationshipChangeTracking { get; }
} 



/// <summary>
/// Adds an object to the object context.
/// </summary>
/// <param name="entitySetName">Represents the entity set name, which may optionally be qualified by the entity container name. </param><param name="entity">The <see cref="T:System.Object"/> to add.</param><exception cref="T:System.ArgumentNullException">The <paramref name="entity"/> parameter is null. -or-The <paramref name="entitySetName"/> does not qualify.</exception>
public void AddObject(string entitySetName, object entity)
{
  EntityUtil.CheckArgumentNull<object>(entity, "entity");
  EntityEntry existingEntry;
  IEntityWrapper wrappedEntity = EntityWrapperFactory.WrapEntityUsingContextGettingEntry(entity, this, out existingEntry);
  if (existingEntry == null)
    this.MetadataWorkspace.ImplicitLoadAssemblyForType(wrappedEntity.IdentityType, (Assembly) null);
  EntitySet entitySet;
  bool isNoOperation;
  this.VerifyRootForAdd(false, entitySetName, wrappedEntity, existingEntry, out entitySet, out isNoOperation);
  if (isNoOperation)
    return;
  System.Data.Objects.Internal.TransactionManager transactionManager = this.ObjectStateManager.TransactionManager;
  transactionManager.BeginAddTracking();
  try
  {
    RelationshipManager relationshipManager = wrappedEntity.RelationshipManager;
    bool flag = true;
    try
    {
      this.AddSingleObject(entitySet, wrappedEntity, "entity");
      flag = false;
    }
    finally
    {
      if (flag && wrappedEntity.Context == this)
      {
        EntityEntry entityEntry = this.ObjectStateManager.FindEntityEntry(wrappedEntity.Entity);
        if (entityEntry != null && entityEntry.EntityKey.IsTemporary)
        {
          relationshipManager.NodeVisited = true;
          RelationshipManager.RemoveRelatedEntitiesFromObjectStateManager(wrappedEntity);
          RelatedEnd.RemoveEntityFromObjectStateManager(wrappedEntity);
        }
      }
    }
    relationshipManager.AddRelatedEntitiesToObjectStateManager(false);
  }
  finally
  {
    transactionManager.EndAddTracking();
  }
}

【讨论】:

  • 这回答了第二部分,但是第一部分呢?
  • 添加是默认跟踪的更改。对象被引用而不被复制
  • 但我试图比较我为插入传递的对象与 ObjectStateManager 中的对象之间的引用,它们并不相同。
  • 真的,它是在引用之前克隆的吗?好,谢谢 。一直认为这是一个真实的参考。是时候调试它了。
  • //我刚刚运行了一个测试,我的测试显示使用了相同的对象。 var t1 = 新租户(); var g = Guid.NewGuid(); t1.Id = g; t1.FirstName = "我的名字是"; uluw.Context.Set().Add(t1); t1.LastName = "如果打印,则引用相同"; var t2 = uluw.Context.Set().Local.Where(ten => ten.Id == g).FirstOrDefault(); Console.WriteLine(t2.LastName);
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-30
  • 1970-01-01
  • 1970-01-01
  • 2017-09-01
  • 2014-05-23
相关资源
最近更新 更多