【发布时间】:2017-06-01 06:11:03
【问题描述】:
注意:
- 我的应用程序 (asp.net mvc) 在层上分离以实现松散耦合。
- 实体 krt_Naftan 和 ScrollLineDTO 具有相同的属性并在不同的层中使用。我使用 Automapper 在它们之间进行转换。
- 我想在 LINQ to SQL(表达式树)中使用一些谓词 (
x => x.DTBUHOTCHET == '01.01.2016')。
它适用于函数:
Func<ScrollLineDTO, bool> predicate = x => x.DTBUHOTCHET == '01.01.2016';
Func<krt_Naftan, bool> func = x => predicate(Mapper.Map<ScrollLineDTO>(x));
因为我无法将 func 包装到表达式树(LINQ to SQL) //不适用于EF6
Expression<Func<krt_Naftan, bool>> filter = x => func(x);
我尝试在表达式中转换类型(编译错误)
Expression<Func<ScrollLineDTO, bool>> predicate = x => x.DTBUHOTCHET == '01.01.2016';
Expression<Func<krt_Naftan, bool>> func = x =>predicate(Mapper.Map<ScrollLineDTO>(x));
问题:如何将转换功能用于表达式树语句?或者可能需要别的东西;)
1) 索引方法(UI层)
public ActionResult Index(DateTime? period = null, int page = 1, bool asService = false, ushort initialSizeItem = 15) {
if (Request.IsAjaxRequest()) {
long recordCount;
//default
Expression<Func<ScrollLineDTO, bool>> predicate = x => x.DTBUHOTCHET == (period == null ? new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1) : period);
var result = new IndexMV() {
ListKrtNaftan = _bussinesEngage.SkipTable(page, initialSizeItem, out recordCount, predicate),
...
}
};
....
2)(BLL层)
public IEnumerable<T> SkipTable<T>(int page, int initialSizeItem, out long recordCount, Expression<Func<T, bool>> predicate = null) {
if (predicate == null) {
//convert func types
Expression<Func<krt_Naftan, bool>> func = x => predicate(Mapper.Map<ScrollLineDTO>(x));
//wrap in func to expression (is not impossible, maybe if pass method...)
//Expression<Func<krt_Naftan, bool>> filter = x => func(x);
return (IEnumerable<T>)Mapper.Map<IEnumerable<ScrollLineDTO>>(Engage.GetSkipRows(page, initialSizeItem, out recordCount, x => x.KEYKRT, func));
}
return (IEnumerable<T>)Mapper.Map<IEnumerable<ScrollLineDTO>>(Engage.GetSkipRows<krt_Naftan, long>(page, initialSizeItem, out recordCount, x => x.KEYKRT));
}
/// <summary>
/// Return pagging part of table and general count of rows
/// </summary>
/// <typeparam name="T">Current enity</typeparam>
/// <typeparam name="TKey">Type for ordering</typeparam>
/// <param name="page">Number page</param>
/// <param name="size">Count row per one page</param>
/// <param name="recordCount"></param>
/// <param name="orderPredicate">Condition for ordering</param>
/// <param name="filterPredicate">Condition for filtering</param>
/// <param name="caсhe"></param>
/// <returns>Return definition count rows of specific entity</returns>
public IEnumerable<T> GetSkipRows<T, TKey>(int page, int size, out long recordCount, Expression<Func<T, TKey>> orderPredicate, Expression<Func<T, bool>> filterPredicate = null, bool caсhe = false) where T : class {
recordCount = GetCountRows(filterPredicate);
using (Uow = new UnitOfWork()) {
return Uow.Repository<T>().Get_all(filterPredicate, caсhe).OrderByDescending(orderPredicate).Skip((page - 1) * size).Take(size).ToList();
}
}
3)(DLL层)从db获取数据
/// <summary>
/// Get lazy data set (with cashing or not (attr MergeOption )
/// </summary>
/// <param name="predicate">filter condition for retrieving data from source(database)</param>
/// <param name="enableDetectChanges">Compare two snapshot of data (one when retrieve data from database other when call method saveChanges(). If exists some diffrences => generate avaible SQL command</param>
/// <param name="enableTracking"></param>
/// <returns></returns>
public IQueryable<T> Get_all(Expression<Func<T, bool>> predicate = null, bool enableDetectChanges = true, bool enableTracking = true) {
/*//sync data in Db & EF (if change not tracking for EF)
((IObjectContextAdapter)_context).ObjectContext.Refresh(RefreshMode.StoreWins, _dbSet.Where(predicate));
_context.Entry(_dbSet.Where(predicate)).Reload(); EF 4.1+*/
ActiveContext.Configuration.AutoDetectChangesEnabled = enableDetectChanges;
if (predicate == null) return (enableTracking) ? _dbSet : _dbSet.AsNoTracking();
var result = (enableTracking) ? _dbSet.Where(predicate) : _dbSet.AsNoTracking().Where(predicate);
return result;
}
谢谢)
【问题讨论】:
-
什么不起作用,你想做什么?你为什么要转换表达式? Linq to SQL 可能允许将所有内容加载到内存中的表达式。 Linq to EF 正确地阻止了这些并引发异常。
-
你为什么用表达式而不是写作,例如
myQuery=myQuery.Where(x=> x.DTBUHOTCHET == "01.01.2016");?看起来您正在尝试创建某种动态标准,但这可以通过使用不同的Where语句轻松完成 -
是的,我有“通用”服务来请求 Db 我使用通用方法(独立于实体类型和 lambda 谓词类型)。即 IEnumerable
GetSkipRows (int page, int size, out long recordCount, Expression > orderPredicate, Expression > filterPredicate = null, bool caсhe = false ) 其中 T : 类; -
你为什么不简单地添加一个电话到
.Where()?实际的数据访问代码在哪里?为什么要在类型之间进行转换?此外,predicate(Mapper.Map<ScrollLineDTO>(x)永远无法转换为 SQL - is 那里的表达式是什么? SQL Server 在哪里可以找到Mapper.Map?如果这适用于 LINQ to SQL,那是因为 LINQ to SQL 将所有xs 加载到内存中,然后将谓词应用于它们,导致性能很差。 -
它通过工作单元模式工作
标签: c# linq mapping expression func