C# DbSet<;tenty>;。本地vs DbContext.ChangeTracker

C# DbSet<;tenty>;。本地vs DbContext.ChangeTracker,c#,entity-framework,repository,dbcontext,C#,Entity Framework,Repository,Dbcontext,在一次会议上,我要求澄清何时使用DbSet.Local。我还没有得到答案,我想这个问题可能包含了太多的信息。在深入挖掘之后,我可以问一个更具体的问题 希望你们能解释一下在我的场景中选择哪两个选项 我想要实现什么? 我正在尝试从我的存储库中检索实体。实体仍处于“添加”状态(即,我尚未调用SaveChanges方法)。我需要这个,因为我想在一个原子操作中存储实体,所以我必须将SaveChanges调用推迟到我验证完整模型之后 此外,我还需要遵循IQueryable接口,因为我有使用扩展方法Inclu

在一次会议上,我要求澄清何时使用
DbSet.Local
。我还没有得到答案,我想这个问题可能包含了太多的信息。在深入挖掘之后,我可以问一个更具体的问题

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

我想要实现什么?
  • 我正在尝试从我的
    存储库
    中检索实体。实体仍处于“添加”状态(即,我尚未调用
    SaveChanges
    方法)。我需要这个,因为我想在一个原子操作中存储实体,所以我必须将
    SaveChanges
    调用推迟到我验证完整模型之后

  • 此外,我还需要遵循IQueryable接口,因为我有使用扩展方法
    Include
    on
    Queryable
    来延迟加载导航属性的依赖代码

  • 我试了什么? 在过去的几天里发生了很多事情,但归结起来有以下两种不同的方法:

    • 通过
      DbSet.Local
      属性检索处于“添加”状态的实体
    • 通过
      DbContext.ChangeTracker
    可视化不同方法的代码示例
    public void addandRetrieveUncommittedIdentityFromDBContext()
    {
    SetInitializer(新的DropCreateDatabaseAlways());
    var testContext=newtestcontext();
    //初始化实体并将其存储在存储库中
    var-tenant=new-tenant{Name=“test”,Guid=Guid.NewGuid().ToString()};
    var user=新用户{Name=“bas”,EmailAddress=”bas@domain.com,Password=“Password”};
    tenant.Users.Add(用户);
    testContext.Tenants.Add(租户);
    //注意:我还没有调用'SaveChanges',但我仍然想检索
    //我的存储库中的租户
    ///////////////////////////////////////////////
    //备选方案一,使用ChangeTracker//
    ///////////////////////////////////////////////
    IEnumerable tenants=testContext.ChangeTracker.Entries();
    IQueryable query=tenants.Select(dbEntityEntry=>dbEntityEntry.Entity).AsQueryable();
    租户storedTenant=查询。
    其中(ent=>ent.Name.Equals(“test”))。
    Include(ent=>ent.Users).First();
    Assert.IsNotNull(storedTenant.Users.FirstOrDefault());
    //万岁,它过去了
    ///////////////////////////////////////////////
    //备选方案二,使用“本地”属性//
    ///////////////////////////////////////////////
    IQueryable query2=testContext.Tenants.Local.AsQueryable();
    租户storedTenant2=查询2。
    其中(ent=>ent.Name.Equals(“test”))。
    Include(ent=>ent.Users).First();
    Assert.IsNotNull(storedTenant2.Users.FirstOrDefault());
    //万岁,它过去了
    ////////////////////////////////////////////////
    //为了完整性=>实体不在DbSet中//
    ////////////////////////////////////////////////
    IQueryable query3=testContext.Tenants.AsQueryable();
    租户存储的Tenant3=查询3。
    其中(ent=>ent.Name.Equals(“test”))。
    Include(ent=>ent.Users).FirstOrDefault();
    Assert.IsNotNull(storedTenant3);
    //失败,因为该实体在数据库集“testContext.Tenants”中尚不可用
    }
    
    testContext非常简单:

    public class TestContext : DbContext
    {
        public DbSet<User> Users { get; set; }
        public DbSet<Tenant> Tenants { get; set; }
    
        public TestContext() : base("Test1") {}
    }
    
    公共类TestContext:DbContext
    {
    公共数据库集用户{get;set;}
    公共数据库集租户{get;set;}
    公共TestContext():基(“Test1”){}
    }
    
    问题
    • 检索所有实体(即包括处于“添加”状态的实体)的建议方法是什么
    • DbSet.Local
      ChangeTracker
      的优缺点是什么

    非常感谢

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

    如果您不确定所有被跟踪的实体都处于添加状态,则
    ChangeTracker
    可让您通过
    EntityState筛选
    DbEntityEntry
    s。添加的
    ,然后获取对要处理的实际实体的引用

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

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

    如果这些都是为了执行验证,那么还有其他方法可以进行验证,其中一些方法可以阅读。

    您是否手动生成这些注释(
    ///../code>)?(只是好奇)。是的,这是超级跛脚的,因为当我键入//.thx时,VisualStudio可以帮我做到这一点,为您提供清晰的解释。我不是在寻找“添加的”实体集,而是在寻找我的系统已知的“所有”实体。我希望通过
    DbSet
    返回的内容。因此,我不能完全确定我现在是否有正确的答案。我现在的看法是,我从不需要
    DbSet
    ,但我总是需要
    DbSet.Local
    。但话说回来,不是每个人都想检索他们系统已知的所有实体吗?那么我为什么要使用
    DbSet
    。我说的有道理吗,还是我完全错了?谢谢你的帮助+1如果需要跟踪的实体,则可以查询本地集合,但显然仍需要数据库集进行数据库访问。我觉得您的存储库/上下文存在的时间太长了,这就是为什么您在本地和本地之间存在这种困境
    foreach(var entity in collection)
    {
      if(context.entry(entity).State == EntityState.Added)
      {
      //do stuff...
      }
    }