如何动态构建entity framework查询?
我对Entity Framework很新,我对过滤数据有疑问。
我有两个不同的Log实体,它们是: DiskLog
和NetworkLog
。 这些实体都是从Log
实体派生的。 以下是我的C#应用程序中的一些代码:
public class Log { ... } public class DiskLog : Log { ... } public class NetworkLog : Log { ... } public enum LogType { NotInitialized = 0, Disk, Network } public List 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工作。 我有几种执行方式:
-
if logType == LogType.Disk && computerId <= 0
(这意味着查询中不需要使用computerId参数,只选择DiskLog实体) -
if logType == LogType.Disk && computerId > 0
(意味着我必须使用computerId参数,请仅选择DiskLog实体) -
if logType == LogType.NotInitialized && computerId <= 0
(不需要使用computerId和logType,只需选择所有实体,DiskLog和NetworkLog) -
if logType == LogType.NotInitialized && computerId > 0
(为指定的计算机选择所有类型的日志) -
if logType == LogType.Network && computerId <= 0
(选择所有NetworkLog实体) -
if logType == LogType.Network && computerId > 0
(为指定的计算机选择所有NetworkLog实体)
如您所见,有很多可用的选项。 我要编写6个这样的查询:
1。
context.LogSet .OfType .Where(x => x.Computer.User.UserKey == userKey) .Where(x => x.DateStamp >= dateFrom && x.DateStamp x.Id) .Skip(nSkip) .Take(nTake) .ToList();
2。
context.LogSet .OfType .Where(x => x.Computer.User.UserKey == userKey) .Where(x => x.DateStamp >= dateFrom && x.DateStamp 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 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 x.Computer.Id == computerId) .OrderByDescending(x => x.Id) .Skip(nSkip) .Take(nTake) .ToList();
5。
context.LogSet .OfType .Where(x => x.Computer.User.UserKey == userKey) .Where(x => x.DateStamp >= dateFrom && x.DateStamp x.Id) .Skip(nSkip) .Take(nTake) .ToList();
6。
context.LogSet .OfType .Where(x => x.Computer.User.UserKey == userKey) .Where(x => x.DateStamp >= dateFrom && x.DateStamp x.Computer.Id == computerId) .OrderByDescending(x => x.Id) .Skip(nSkip) .Take(nTake) .ToList();
所以问题是如何优化代码? 如何让它变得更好。
您可以轻松使用查询组合。
首先从查询开始。
IQueryable query = context.LogSet;
他们组成子查询。
if (logType == LogType.Disk) { query = query.OfType(); // not sure if you need conversion here } else if (logType == LogType.Network) { query = query.OfType(); // 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;
当没有值时,我会建议使用可空值的类型作为案例。
您可以使用Func
来优化它
IEnumerable Select (IEnumerable source, Func userKeyFunc, Func dateFunc, int skip, int take) { return source.OfType ().Where(userKeyFunc).Where(dateFunc).Skip(skip).Take(take); }
然后使用:
var result = Select(context.LogSet,x => x.Computer.User.UserKey == userKey, x => x.DateStamp >= dateFrom && x.DateStamp < dateTo, nSkip,nTake)
您可以为此function创建工厂