2011-05-04 51 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