使用泛型的实体框架相关对象

时间:2015-02-12 15:12:17

标签: c# linq entity-framework-6

在将Linq用于实体时,有关使用Include()和Load()来获取相关表信息的问题很多。我对这个问题有不同的看法。

我的情况:

我有一个表,其中包含系统中每个用户的许多时间记录,并且我使用存储库模式和泛型进行开发,因此我的所有实体都有一个用于标准方法调用的接口。我关闭了延迟加载,我自己加载所有数据。因此,存储库中用于从具有相关表的表中加载所有记录的代码如下所示:

public class Repository<T> : IRepository<T> where T : class
{
    protected readonly ApplicationDbContext Context;

    public Repository(IConnectionHelper connection)
    {
        Context = connection.Context;
    }
    public virtual DbSet<T> ObjectSet
    {
        get { return Context.Set<T>(); }
    }  
    public List<T> GetAll(String[] include, Expression<Func<T, bool>> predicate)
    {
        DbQuery<T> outQuery = null;
        foreach (String s in include)
        {
            outQuery = ObjectSet.Include(s);
            outQuery.Load();
        }
        return outQuery.Where(predicate).ToList();
    }
}

对方法的调用如下:

string[] includes = { "User.UserProfile", "CampaignTimeClocks.CampaignRole.Campaign", "Site", "Type" };
DateTime uTcCurrent = GetUtc();
DateTime MinClockinDate = uTcCurrent.AddHours(-10);
List<TimeClock> tcPending = _timeClock.GetAll(includes, x => (x.PendingReview || x.ClockInDate < MinClockinDate && x.ClockOutDate == null) && (x.Site.Id == currentUser.SiteId));

当此方法运行并加载第一个User.Profile表时,它会加载所有时钟记录并将它们与所有用户相关联,这需要花费一分钟,这太长了,因为结束记录count只有185条记录,但是查询的初始加载运行了27,000 * 560个用户,或者1500万条记录,而且随着时间的推移,这只会变得更糟。

问题是我如何在没有这种负载开销的情况下做到这一点,我知道我可以链接包含,但由于包含的数量将根据我所做的数据和所调用的数据而改变,我不能简单地硬编码包含链。

我也尝试过:

List<TimeClock> testLst =  _timeClock.GetAll(x => x.PendingReview || 
     (x.ClockInDate < MinClockinDate && x.ClockOutDate == null))
          .Select(x => new TimeClock{Id = x.Id,
                                     ClockInDate = x.ClockInDate, 
                                     ClockOutDate = x.ClockOutDate,
                                     TotalClockTime = x.TotalClockTime,
                                     Notes = x.Notes, 
                                     PendingReview = x.PendingReview, 
                                     Type = x.Type,
                                     User = x.User, 
                                     CampaignTimeClocks = x.CampaignTimeClocks,
                                     TimeClockAdjustments = x.TimeClockAdjustments,
                                     Site = x.User.Site}).ToList();

这将为我提供User.Profile信息,但Site和Type属性为null。

所以我对如何加载我需要的数据感到有点迷茫。

非常感谢所有帮助。

3 个答案:

答案 0 :(得分:0)

你能先获得初始名单

吗?
List<TimeClock> testLst =  _timeClock.Where(x => x.PendingReview || (x.ClockInDate < MinClockinDate && x.ClockOutDate == null)).ToList();

然后调用一个以T为参数的修改后的GetAll()

答案 1 :(得分:0)

您执行的每个包含都将最终在数据库中执行连接。 假设您的左表是非常大的1024字节的记录大小,并且您有许多细节,比如1000,并且详细记录大小只有100。 这将导致左表的信息重复1000次,这些信息将由db放在线上,EF必须过滤掉重复的内容以创建左实例。

最好不要使用include并进行显式加载。基本上在同一个上下文中执行2个查询。

我有一个这样的例子,与你的不同,但我希望你能得到这个想法。它可以比依赖包含快10倍。 (数据库只能有效地处理有限数量的连接)

var adressen = adresRepository
                .Query(r => r.RelatieId == relatieId)
                .Include(i => i.AdresType)
                .Select().ToList();

var adresids = (from a in adressen select a.AdresId).ToList();
            IRepositoryAsync<Comm> commRepository = unitOfWork.RepositoryAsync<Comm>();

            var comms = commRepository
                .Query(c => adresids.Contains(c.AdresId))
                .Include(i => i.CommType)
                .Select();

对于commType和adresType,我使用include,因为存在1对1的关系,我避免了太多的连接,因此我的多个查询将比使用include的单个查询更快。我没有在第一个查询中包含Comms来尝试避免第二个查询,重点是在这种情况下2个查询比单个查询更快。

请注意,我的代码是使用我自己的存储库构建的,因此这段代码对您不起作用,但您可以了解这一点。

答案 2 :(得分:0)

我发现在不使用Load()语句的情况下更有效地执行此操作的方法是将DBQuery更改为IQueryable并链接包含,并返回执行的查询结果,并一起删除DBQuery.Load() 。这将查询的执行时间从秒改为毫秒。

    public List<T> GetAll(String[] include)
    {
        IQueryable<T> outQuery = ObjectSet;
        foreach (String s in include)
        {
            outQuery = outQuery.Include(s);
        }
        return outQuery.ToList();
    }
相关问题