пятница, 9 сентября 2011 г.

Компилированные запросы Linq (Compiled query) и ADO.Net 4.0

Многие пытаются сравнить производительность Entity Framework с чистым SQL. В любом случае запрос выполненный с помощью прямого SQL запроса будет быстрее чем использование LINQ хотя бы за счет маппинга полей.

Но эту разницу можно сократить до минимума. В EF 4.0 Linq запрос компилируются (разбираются) каждый раз когда к ним обращаются. Сама по себе эта операция дорогостоящая и мы должны от нее избавиться.

Делается это с помощью класса CompiledQuery

Класс CompiledQuery имеет статический метод Compile, параметром которому идет выражение Linq. Результатом этой функции является делегат. Его и вызываем когда нужно получить данные через запрос.

Пример:

//делегат, с помощью которого будет вызываться наш запрос



Func <telephonyEntities1, int, List<int>, IQueryable<CallComment  _compiledCallCommentsGet = null;


        public List CallCommentsGet(CallDetail callDetail)
        {
            if (callDetail == null)
                throw new ArgumentNullException("callDetail", "callDetail не должен быть null");
            if (callDetail.id <= 0)
                throw new ArgumentException("callDetail.ID", "callDetail должен иметь ID");




            List list = null;
            var context = GetSqlConnection();
//Смотрим создавали ли мы уже скомпилированный linq запрос
            if (_compiledCallCommentsGet == null)
            {
//сам процесс создания делегата
                _compiledCallCommentsGet = CompiledQuery.Compile
<telephonyEntities1, int, List<int>, IQueryable<CallComment  (
                    (ctx, id) =>
                from c in ctx.CallComments
                where c.CallDetail.id == callDetail.id
                orderby c.dateWhen descending
                select c);
            }
//вызываем linq запрос через наш делегат
            list=_compiledCallCommentsGet.Invoke(context, callDetail.id).ToList();
            return list;


        }


Особенности:

К сожалению такую штуку скомпилировать не удастся:


from cd in context.CallDetails
where cd.Call.DateWhen >= dateTimeFrom && cd.Call.DateWhen < dateTimeTo &&
           (listOpInt.Any() == false || listOpInt.Contains(cd.Call.Operator.id))
select cd



потому что "Only scalar parameters (such as Int32, Decimal, and Guid) are supported." ..>.

Комментариев нет:

Отправить комментарий