【问题标题】:How can I build Entity Framework queries dynamically?如何动态构建实体框架查询?
【发布时间】:2011-08-18 09:00:54
【问题描述】:

我是 Entity Framework 的新手,我有一个关于过滤数据的问题。

我有两个不同的 Log 实体,它们是:DiskLogNetworkLog。这些实体都派生自Log 实体。这是我的 C# 应用程序中的一些代码:

public class Log { ... }
public class DiskLog : Log { ... }
public class NetworkLog : Log { ... }

public enum LogType
{
    NotInitialized = 0,
    Disk,
    Network
}

public List<Log> GetWithFilter(
    Guid userKey, 
    int nSkip, 
    int nTake, 
    DateTime dateFrom = DateTime.MinValue, 
    DateTime dateTo = DateTime.MaxValue, 
    LogType logType = LogType.NotInitialized, 
    int computerId = 0)
{
    // need to know how to optimize ...

    return ...
}

当然,我已经创建了工作应用程序和数据库表。我想要做的是使函数 GetWithFilter 工作。我有几种执行方式:

  1. if logType == LogType.Disk &amp;&amp; computerId &lt;= 0(表示查询中不需要使用computerId参数,只选择DiskLog实体)

  2. if logType == LogType.Disk &amp;&amp; computerId &gt; 0(意味着我必须使用computerId参数,只选择DiskLog实体)

  3. if logType == LogType.NotInitialized &amp;&amp; computerId &lt;= 0(无需使用computerId和logType,只需选择所有实体,DiskLog和NetworkLog)

  4. if logType == LogType.NotInitialized &amp;&amp; computerId &gt; 0(选择指定计算机的所有日志类型)

  5. if logType == LogType.Network &amp;&amp; computerId &lt;= 0(选择所有 NetworkLog 实体)

  6. if logType == LogType.Network &amp;&amp; computerId &gt; 0(选择指定计算机的所有 NetworkLog 实体)

如您所见,有很多可用的选项。我必须写 6 个这样的查询:

1.

context.LogSet
    .OfType<DiskLog>
    .Where(x => x.Computer.User.UserKey == userKey)
    .Where(x => x.DateStamp >= dateFrom && x.DateStamp < dateTo)
    .OrderByDescending(x => x.Id)
    .Skip(nSkip)
    .Take(nTake)
    .ToList();

2.

context.LogSet
    .OfType<DiskLog>
    .Where(x => x.Computer.User.UserKey == userKey)
    .Where(x => x.DateStamp >= dateFrom && x.DateStamp < dateTo)
    .Where(x => x.Computer.Id == computerId)
    .OrderByDescending(x => x.Id)
    .Skip(nSkip)
    .Take(nTake)
    .ToList();

3.

context.LogSet
    .Where(x => x.Computer.User.UserKey == userKey)
    .Where(x => x.DateStamp >= dateFrom && x.DateStamp < dateTo)
    .OrderByDescending(x => x.Id)
    .Skip(nSkip)
    .Take(nTake)
    .ToList(); // simplest one!

4.

context.LogSet
    .Where(x => x.Computer.User.UserKey == userKey)
    .Where(x => x.DateStamp >= dateFrom && x.DateStamp < dateTo)
    .Where( x => x.Computer.Id == computerId)
    .OrderByDescending(x => x.Id)
    .Skip(nSkip)
    .Take(nTake)
    .ToList();

5.

context.LogSet
    .OfType<NetworkLog>
    .Where(x => x.Computer.User.UserKey == userKey)
    .Where(x => x.DateStamp >= dateFrom && x.DateStamp < dateTo)
    .OrderByDescending(x => x.Id)
    .Skip(nSkip)
    .Take(nTake)
    .ToList();

6.

context.LogSet
    .OfType<NetworkLog>
    .Where(x => x.Computer.User.UserKey == userKey)
    .Where(x => x.DateStamp >= dateFrom && x.DateStamp < dateTo)
    .Where( x => x.Computer.Id == computerId)
    .OrderByDescending(x => x.Id)
    .Skip(nSkip)
    .Take(nTake)
    .ToList();

所以问题是如何优化代码?改善的方法在哪里。

【问题讨论】:

    标签: c# linq entity-framework filter filtering


    【解决方案1】:

    您可以轻松使用查询组合。

    你首先从查询开始。

    IQueryable<Log> query = context.LogSet;
    

    您编写子查询。

    if (logType == LogType.Disk)
    {
        query = query.OfType<DiskLog>(); // not sure if you need conversion here
    } 
    else if (logType == LogType.Network)
    {
        query = query.OfType<NetworkLog>(); // not sure if you need conversion here
    }
    
    query = query.Where(x => x.Computer.User.UserKey == userKey);
    
    if (computerId != 0)
       query = query.Where( x => x.Computer.Id == computerId);
    
    // .. and so on
    
    query = query.OrderByDescending(x => x.Id).Skip(nSkip).Take(nTake);
    
    return query.ToList(); // do database call, materialize the data and return;
    

    而且我建议在没有值的情况下使用可为空的值类型。

    【讨论】:

      【解决方案2】:

      你可以使用Func&lt;T,bool&gt;来优化这个

      IEnumerable<T> Select<T>(IEnumerable<T> source, Func<T, bool> userKeyFunc, Func<T, bool> dateFunc, int skip, int take)
      {
          return source.OfType<T>().Where(userKeyFunc).Where(dateFunc).Skip(skip).Take(take);
      }
      

      然后使用:

      var result = Select<NetworkLog>(context.LogSet,x => x.Computer.User.UserKey == userKey,
                                      x => x.DateStamp >= dateFrom && x.DateStamp < dateTo, nSkip,nTake)
      

      您可以为此功能创建工厂

      【讨论】:

      • 应该是 Expression。这将过滤内存中的数据。
      猜你喜欢
      • 2011-07-29
      • 1970-01-01
      • 1970-01-01
      • 2020-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-31
      相关资源
      最近更新 更多