2011-05-04 50 views
10

我对Entity Framework相当陌生,我对过滤数据有疑问。我该如何动态构建实体框架查询?

我有两个不同的日志实体,它们是: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 && 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(); 

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(); 

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

回答

12

您可以轻松地使用查询compossition您可以创建工厂。

您首先开始查询。

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; 

我会推荐使用可为空的值类型的情况下,当没有价值。

6

您可以使用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); 
} 

然后使用:

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

而且这个功能

+4

这应该是表达式。这将过滤内存中的数据。 – Euphoric 2011-05-04 10:40:54