如何动态构建实体框架查询?

Rom*_*kin 11 c# linq entity-framework filtering filter

我对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 ...
}
Run Code Online (Sandbox Code Playgroud)

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

  1. if logType == LogType.Disk && computerId <= 0 (这意味着查询中不需要使用computerId参数,只选择DiskLog实体)

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

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

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

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

  6. if logType == LogType.Network && computerId > 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();
Run Code Online (Sandbox Code Playgroud)

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();
Run Code Online (Sandbox Code Playgroud)

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!
Run Code Online (Sandbox Code Playgroud)

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();
Run Code Online (Sandbox Code Playgroud)

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();
Run Code Online (Sandbox Code Playgroud)

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();
Run Code Online (Sandbox Code Playgroud)

所以问题是如何优化代码?如何让它变得更好.

Eup*_*ric 13

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

首先从查询开始.

IQueryable<Log> query = context.LogSet;
Run Code Online (Sandbox Code Playgroud)

他们组成子查询.

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;
Run Code Online (Sandbox Code Playgroud)

当没有值时,我会建议使用可为空的值类型作为案例.


Ste*_*cya 7

您可以使用它Func<T,bool>来优化它

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);
}
Run Code Online (Sandbox Code Playgroud)

然后使用:

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

您可以为此功能创建工厂

  • 这应该是Expression <Func ..>.这将过滤内存中的数据. (5认同)