Примечание:типа Преобразовать в Expression <Func <T1, bool>> в Expression <Func <T2, bool>> (LINQ к SQL)
- Мое приложение (asp.net MVC) разделяется на слои для слабосвязанных целей.
- Объект krt_Naftan и ScrollLineDTO имеют одинаковое свойство и используют в разные слои. Я использую Automapper для преобразования между ними.
- Я хотел бы использовать некоторый предикат (
x => x.DTBUHOTCHET == '01.01.2016'
) Недостаток LINQ to SQL (дерево выражений).
Это работа для FUNC:
Func<ScrollLineDTO, bool> predicate = x => x.DTBUHOTCHET == '01.01.2016';
Func<krt_Naftan, bool> func = x => predicate(Mapper.Map<ScrollLineDTO>(x));
Потому что я не могу обернуть FUNC для выражения дерева (LINQ к SQL) // не работает EF6
Expression<Func<krt_Naftan, bool>> filter = x => func(x);
I попробуйте преобразовать тип в выражения (ошибка компиляции)
Expression<Func<ScrollLineDTO, bool>> predicate = x => x.DTBUHOTCHET == '01.01.2016';
Expression<Func<krt_Naftan, bool>> func = x =>predicate(Mapper.Map<ScrollLineDTO>(x));
Вопрос: Как я могу использовать функцию преобразования для выражений дерева выражений? или, возможно, необходимо что-то еще;)
1) Метод индекса (ПИ слой)
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) (слой БЛЛ)
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-слой) получить данные из БД
/// <summary>
/// Get lazy data set (with cashing or not (attr MergeOption)
/// </summary>
/// <param name="predicate">filter condition for retriew data from source(database)</param>
/// <param name="enableDetectChanges">Compare two snapshot of data (one when retriew 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 i, использую общий метод (не относящийся к типу объекта и тип лямбда-предиката). т.е. IEnumerable GetSkipRows (int page, int size, out long recordCount, Expression > orderPredicate, Expression > filterPredicate = null, bool caсhe = false) где T: class; –
AllmanTool