different post 中,我要求澄清何时使用 DbSet<TEntity>.Local 。我还没有得到答案,我认为这个问题可能包含太多信息。在深入挖掘之后,我可以问一个更具体的问题。

希望你们能解释在我的场景中选择两个选项中的哪一个。

我想要达到什么目标?

  • 我正在尝试从我的 Repository 中检索实体。实体仍处于“添加”状态(即我还没有调用 SaveChanges 方法)。我需要这个,因为我想将实体存储在一个原子操作中,所以我必须将 SaveChanges 调用推迟到我验证完整模型之后。
  • 更进一步,我需要符合 IQueryable 接口(interface),因为我有使用 Include 上的扩展方法 Queryable 来延迟加载导航属性的依赖代码。

  • 我尝试了什么?

    过去几天的事情很多,但归结为以下两种不同的方法:
  • 通过 DbSet<TEntity>.Local 属性
  • 检索处于“添加”状态的实体
  • 通过 DbContext.ChangeTracker
  • 检索处于“添加”状态的实体

    可视化不同方法的代码示例
        public void AddAndRetrieveUncommittedEntityFromDbContext()
        {
            Database.SetInitializer(new DropCreateDatabaseAlways<TestContext>());
            var testContext = new TestContext();
    
            // Initialize the entities and store them in the repository
            var tenant = new Tenant { Name = "test", Guid = Guid.NewGuid().ToString() };
            var user = new User { Name = "bas", EmailAddress = "bas@domain.com", Password = "password" };
            tenant.Users.Add(user);
            testContext.Tenants.Add(tenant);
    
            // NOTE: I did not call `SaveChanges` yet, but still I want to retrieve
            // the tenant from my repository
    
            ///////////////////////////////////////////////
            // Alternative one, use the ChangeTracker... //
            ///////////////////////////////////////////////
            IEnumerable<DbEntityEntry<Tenant>> tenants = testContext.ChangeTracker.Entries<Tenant>();
            IQueryable<Tenant> query = tenants.Select(dbEntityEntry => dbEntityEntry.Entity).AsQueryable();
            Tenant storedTenant = query.
                Where(ent => ent.Name.Equals("test")).
                Include(ent => ent.Users).First();
    
            Assert.IsNotNull(storedTenant.Users.FirstOrDefault());
            // hurray, it passes
    
            ///////////////////////////////////////////////
            // Alternative two, use the 'Local' property //
            ///////////////////////////////////////////////
            IQueryable<Tenant> query2 = testContext.Tenants.Local.AsQueryable();
            Tenant storedTenant2 = query2.
                Where(ent => ent.Name.Equals("test")).
                Include(ent => ent.Users).First();
    
            Assert.IsNotNull(storedTenant2.Users.FirstOrDefault());
            // hurray, it passes
    
            ////////////////////////////////////////////////
            // For completeness => entity is not in DbSet //
            ////////////////////////////////////////////////
    
            IQueryable<Tenant> query3 = testContext.Tenants.AsQueryable();
            Tenant storedTenant3 = query3.
                Where(ent => ent.Name.Equals("test")).
                Include(ent => ent.Users).FirstOrDefault();
    
            Assert.IsNotNull(storedTenant3);
            // Fails, because the entity is not yet available in the DbSet 'testContext.Tenants'
        }
    

    testContext 非常简单:
    public class TestContext : DbContext
    {
        public DbSet<User> Users { get; set; }
        public DbSet<Tenant> Tenants { get; set; }
    
        public TestContext() : base("Test1") {}
    }
    

    问题
  • 检索所有实体(即包括处于“已添加”状态的实体)的建议方法是什么?
  • DbSet<TEntity>.LocalChangeTracker 的优缺点是什么?

  • 非常感谢提前!

    最佳答案

    这真的取决于你想做什么。您的代码都没有专门通过 DbEntityEntry.State 过滤,因此我假设您确定上下文跟踪的所有实体都处于添加状态。

    如果您不确定所有跟踪的实体都处于添加状态,那么 ChangeTracker 使您有机会通过 DbEntityEntry 过滤 EntityState.Added s,然后获取对实际实体的引用以进行处理。

    使用 Local 您可以获得实体本身的 ObservableCollection<T>。如果您确定它们都处于添加状态,那么这可能是最简单的。如果您不确定,那么您必须枚举集合并从上下文中获取 DbEntityEntry 以确保:

    foreach(var entity in collection)
    {
      if(context.entry(entity).State == EntityState.Added)
      {
      //do stuff...
      }
    }
    

    如果这就是执行验证的全部内容,那么还有其他方法可以进行,其中一些可以读取 here

    关于c# - DbSet<TEntity>.Local 与 DbContext.ChangeTracker,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15101196/

    10-13 07:12