EF6每个查询加载指定的子实体

时间:2017-05-10 12:25:59

标签: c# sqlite entity-framework-6

我有一个类,它使用EF6从SQLite数据库中检索数据。

上下文正在构造函数中注入,并且相同上下文被多次用于同一个类实例。我正在使用实体框架6的Include扩展方法在查询中包含子实体。要包含的项目在参数中指定,因此可以根据呼叫者的要求进行更改。

以下是该课程的一个示例:

public class AccountManager
{
    private SQLiteContext context;

    // Injected Context
    public AccountManager(SQLiteContext Context)
    {
        context = Context;
    }

    public Account GetAccountById(int AccountId, string ToInclude)
    {
        return context.Account
                      .Include(ToInclude)
                      .Single(a => a.AccountId == AccountId)
    }
}

问题在于,如果我在第一个查询(查询A)中包含子实体,它可以正常工作,但如果我在后续查询中包含不同的子实体(使用相同的 context )还包括查询A的子实体。例如:

AccountManager am = new AccountManager(MyContext);

// Run first query
var a1 = am.GetAccountById(1, "Payments");

// Run second query
// The result of this query also includes child entity "Payments" 
// because it was added to the context in the previous query
var a2 = am.GetAccountById(1, "Owners");

有没有办法可以防止这种情况发生,并且每个查询的“包含”设置都是唯一处理过的?

3 个答案:

答案 0 :(得分:1)

当Entity Framework从数据库中获取实体时,默认行为是将实体添加到其更改跟踪器中。更改跟踪器不仅跟踪单个实体的更改,还跟踪关联的更改。因此,EF还会填充其更改跟踪缓存中的实体可以找到的任何导航属性。

因此,当您向所有者提取帐户时,EF仍会找到所属的付款,并尽可能填写account.Payments,无论您是否愿意。

我认为在您的情况下,您可以做的最好的事情是在不跟踪的情况下获取实体:

return context.Account.AsNoTracking()
              .Include(ToInclude)
              .Single(a => a.AccountId == AccountId)

现在EF将填充PaymentsOwners,但不会将这些实体添加到其缓存中。在N层应用程序中,在大多数情况下最好使用AsNoTracking,因为几乎不会将更改应用于上下文中的实体,而AsNoTracking执行得更好,因为更新了更改跟踪器和关系修复是昂贵的过程。

或者,您可以将实体标记为EntityState.Detached,但我不会走那条路。

最好的方法是为每个商业交易使用新的上下文,这样你就可以向这个方向发展。

答案 1 :(得分:0)

重要提示:如果您有一对多的关系,我建议您不要这样做。这个很贵。我宁愿创建两个不同的查询。

但是,如果你想这样做,我认为一个更好的选择可能是做一个动态查询,非常有用。这样的事情:

    public Account GetAccountById(int AccountId, bool includePayments = false, bool includeOwners)
  {
        var query = context.Account;

      if(includePayments)
      {
         query = query.Include(c => c.Payments).AsQueryable()
      }

      if(includeOwners)
      {
         query = query.Include(c => c.Owners).AsQueryable()
      }

      return  query.Single(a => a.AccountId == AccountId)
}

答案 2 :(得分:0)

它实际上是为您执行此操作的实体框架的优化。

实体框架在执行查询时构建数据树。

值得问自己为什么要根据这些信息排除这些信息。