Как я могу динамически создавать запросы Entity Framework? - PullRequest
11 голосов
/ 04 мая 2011

Я довольно новичок в Entity Framework и у меня есть вопрос о фильтрации данных.

У меня есть два различных объекта журнала, это: DiskLog и NetworkLog.Эти сущности оба являются производными от сущности 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();

Итак, вопрос в том, как я могу оптимизировать код?Где способ сделать это лучше.

Ответы [ 2 ]

13 голосов
/ 04 мая 2011

Вы можете легко использовать составление запросов.

Сначала вы начинаете с запроса.

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;

И я бы рекомендовал использовать типы значений, допускающие значение NULL, для случаев, когда значение отсутствует.

7 голосов
/ 04 мая 2011

Вы можете использовать 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)

И вы можете создать фабрику для этой функции

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...