2011-05-04 20 views
10

Soy bastante nuevo en Entity Framework y tengo una pregunta sobre el filtrado de datos.¿Cómo puedo crear consultas de Entity Framework dinámicamente?

Tengo dos entidades de registro diferentes, que son: DiskLog y NetworkLog. Estas entidades se derivan de la entidad Log. Aquí hay un código de mi aplicación de 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 ... 
} 

Por supuesto, ya he tablas de aplicaciones y bases de datos de trabajo creados. Lo que quiero hacer es hacer funcionar la función GetWithFilter. Tengo formas varias de ejecución allí:

  1. if logType == LogType.Disk && computerId <= 0 (que significa que no hay necesidad de utilizar el parámetro ComputerID en la consulta, seleccionar sólo las entidades DiskLog)

  2. if logType == LogType.Disk && computerId > 0 (significa que tengo que utilizar el parámetro ComputerID, seleccionar sólo las entidades DiskLog)

  3. if logType == LogType.NotInitialized && computerId <= 0 (sin necesidad de utilizar ComputerID y logType, sólo tiene que seleccionar todas las entidades, DiskLog y NetworkLog)

  4. if logType == LogType.NotInitialized && computerId > 0 (seleccionar todos los tipos de registros de equipo especificado)

  5. if logType == LogType.Network && computerId <= 0 (seleccionar todas las entidades NetworkLog)

  6. if logType == LogType.Network && computerId > 0 (seleccionar todas las entidades NetworkLog de equipo especificado)

Como se puede ver , hay muchas opciones disponibles. Y llegué a escribir 6 consultas como esta:

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

Así que la pregunta es ¿cómo puedo optimizar el código? ¿Dónde está la manera de hacerlo mejor?

Respuesta

12

Usted puede utilizar fácilmente compossition consulta.

Se inicia por primera vez con la consulta.

IQueryable<Log> query = context.LogSet; 

Ellos componen sub-consultas.

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; 

Y recomendaría el uso de tipos de valores que se pueden anular para los casos, cuando no hay ningún valor.

6

Puede utilizar Func<T,bool> para optimizar este

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

A continuación, utilice:

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

Además, puede crear la fábrica para estas funciones

+4

eso se debe Expresión . Esto filtra los datos en memoria. – Euphoric

Cuestiones relacionadas