CompiledQuery
От: fabio Узбекистан  
Дата: 25.02.08 09:19
Оценка:
У нас приложение написано с использованием Linq to SQL но в нем много обращений к базе и большая часть из которых очень сильно похожа.

Наверное слышали про UZTO http://uzto.netdec.uz

Это MDI приложение и для каждого объекта открывается своя форма для редактирования объекта.
У каждой формы свой контекст (DataContext).

Мы решили воспользовать предлагаемой возможностью CompiledQuery!

Но вот проблема при первом выполнение запроса CompiledQuery запоминается контекст, но при последующих выполнениях этого же запроса в другом контексте, он НИЧЕГО не знает о полученных объектах, кажется что он получил результат для старого контекста. По этой причине когда мы пытаемся сохранить объект то он ругается, что объекты из другого контекста и это не поддерживается Linq to SQL.

Текст ошибки:
===================================

An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext.  This is not supported. (System.Data.Linq)

------------------------------
Program Location:

   at System.Data.Linq.ChangeTracker.StandardChangeTracker.Track(MetaType mt, Object obj, Dictionary`2 visited, Boolean recurse, Int32 level)
   at System.Data.Linq.ChangeTracker.StandardChangeTracker.Track(Object obj, Boolean recurse)
   at System.Data.Linq.ChangeTracker.StandardChangeTracker.Track(Object obj)
   at System.Data.Linq.ChangeProcessor.TrackUntrackedObjects(MetaType type, Object item, Dictionary`2 visited)
   at System.Data.Linq.ChangeProcessor.TrackUntrackedObjects(MetaType type, Object item, Dictionary`2 visited)
   at System.Data.Linq.ChangeProcessor.TrackUntrackedObjects()
   at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
   at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
   ...
Re: CompiledQuery
От: Curufinwe Украина  
Дата: 25.02.08 10:14
Оценка:
Здравствуйте, fabio, Вы писали:

F>Мы решили воспользовать предлагаемой возможностью CompiledQuery!


F>Но вот проблема при первом выполнение запроса CompiledQuery запоминается контекст, но при последующих выполнениях этого же запроса в другом контексте, он НИЧЕГО не знает о полученных объектах, кажется что он получил результат для старого контекста. По этой причине когда мы пытаемся сохранить объект то он ругается, что объекты из другого контекста и это не поддерживается Linq to SQL.


Так и должно быть. К CompliledQuery это вообще не имеет никакого отношения.
Прочитанные записи "привязаны" к своему контексту и с другим работать не будут. Есть паттерн такой — Unit of Work — как раз описывает работу с DataContext.
Если же всё-таки очень надо — клонируйте объекты и клоны можно приаттачить к другому контексту.
... << RSDN@Home 1.2.0 alpha rev. 693>>
Re[2]: CompiledQuery
От: fabio Узбекистан  
Дата: 25.02.08 12:15
Оценка:
Здравствуйте, Curufinwe, Вы писали:
>Так и должно быть. К CompliledQuery это вообще не имеет никакого отношения.
>Прочитанные записи "привязаны" к своему контексту и с другим работать не будут. Есть паттерн такой — Unit of Work — как раз описывает работу с DataContext.
>Если же всё-таки очень надо — клонируйте объекты и клоны можно приаттачить к другому контексту.

Если я правильно понимал CompliledQuery -> это сохраненый запрос на базе но не сохраненые записи в памяти приложения.

Вопрос: При клонирование объекта он действительно забывает про свой контекст и готов к Atach.
Re[3]: CompiledQuery
От: Curufinwe Украина  
Дата: 25.02.08 13:09
Оценка:
Здравствуйте, fabio, Вы писали:

F>Если я правильно понимал CompliledQuery -> это сохраненый запрос на базе но не сохраненые записи в памяти приложения.


Не совсем. В CompliledQuery хранится сгенерированный из Linq выражения SQL запрос, в который только осталось подставить параметры. Это позволяет не делать каждый раз идентичное преобразование Linq expression -> SQL query. БД как таковая в этом никак не учавствует.

F>Вопрос: При клонирование объекта он действительно забывает про свой контекст и готов к Atach.


Да, проверено на практике.
... << RSDN@Home 1.2.0 alpha rev. 693>>
Re[4]: CompiledQuery
От: fabio Узбекистан  
Дата: 25.02.08 16:29
Оценка:
Здравствуйте, Curufinwe, Вы писали:

F>>Если я правильно понимал CompliledQuery -> это сохраненый запрос на базе но не сохраненые записи в памяти приложения.

C>Не совсем. В CompliledQuery хранится сгенерированный из Linq выражения SQL запрос, в который только осталось подставить параметры. Это позволяет не делать каждый раз идентичное преобразование Linq expression -> SQL query. БД как таковая в этом никак не учавствует.
F>>Вопрос: При клонирование объекта он действительно забывает про свой контекст и готов к Atach.
C>Да, проверено на практике.

А есть вариант сохранить скомпилированные запросы на Базе (по средствам Linq to SQL) чтоб еще поднять скорость исполнения?

Спасибо. За то что помогаете разобраться. Ато в инете нет нормальное объяснения.
Re[5]: CompiledQuery
От: Curufinwe Украина  
Дата: 25.02.08 16:46
Оценка: 2 (1)
Здравствуйте, fabio, Вы писали:

F>А есть вариант сохранить скомпилированные запросы на Базе (по средствам Linq to SQL) чтоб еще поднять скорость исполнения?


MSSQL самостоятельно кеширует скомпилированные запросы, если они одинаковые (т.е. текст запроса одинаковый, но параметры могут отличаться), так что делать что-то дополнительно здесь не надо

F>Спасибо. За то что помогаете разобраться. Ато в инете нет нормальное объяснения.


Для спасибо кнопочка есть
... << RSDN@Home 1.2.0 alpha rev. 693>>
Re: CompiledQuery
От: fabio Узбекистан  
Дата: 05.03.08 15:06
Оценка:
Здравствуйте, fabio, Вы писали:

В продолжение вопросов по CompiledQuery.

Так-как CompiledQuery в сформированные запросы подставлются параменты, то мы решили что можно передавать масивы при условии соответствия одному из значений:
на SQL:

     select * from dbo.City
      where id in (2,5,7,12)



на Linq to Sql:

    var list = new int[]{2,5,7,12};
    Context.GetTable<City>().Where(wr=>list.Contains(wr.ID)).ToList();



Мы попробовали использовать данную конструкцию в запросах CompiledQuery.
-- И он дает ошибку --

Может кто-нибудь уже пробовал? Помогите.
Re[2]: CompiledQuery
От: Curufinwe Украина  
Дата: 05.03.08 15:36
Оценка:
Здравствуйте, fabio, Вы писали:

F>Так-как CompiledQuery в сформированные запросы подставлются параменты, то мы решили что можно передавать масивы при условии соответствия одному из значений:

F>на SQL:

F>
F>     select * from dbo.City
F>      where id in (2,5,7,12)
F>



F>на Linq to Sql:


F>
F>    var list = new int[]{2,5,7,12};
F>    Context.GetTable<City>().Where(wr=>list.Contains(wr.ID)).ToList();
F>



F>Мы попробовали использовать данную конструкцию в запросах CompiledQuery.

F> -- И он дает ошибку --

F>Может кто-нибудь уже пробовал? Помогите.


Конечно пробовали
list в запросе может содержать разное количество данных, а при компиляции запроса количество параметров должно быть известно заранее поэтому на любую конструкцию list.Contains он ругается.
Лучший вариант не использовать CompiledQuery для подобных запросов.
Можно использовать raw SQL если скорость очень критична.
Есть конечно другое "полурешение" этой проблеммы с использованием CompiledQuery, но с очень большим гемороем, так что даже рассказывать не хочется
... << RSDN@Home 1.2.0 alpha rev. 693>>
Re[3]: CompiledQuery
От: fabio Узбекистан  
Дата: 05.03.08 15:45
Оценка:
Здравствуйте, Curufinwe, Вы писали:

C>Конечно пробовали

C>list в запросе может содержать разное количество данных, а при компиляции запроса количество параметров должно быть известно заранее поэтому на любую конструкцию list.Contains он ругается.
C>Лучший вариант не использовать CompiledQuery для подобных запросов.
C>Можно использовать raw SQL если скорость очень критична.
C>Есть конечно другое "полурешение" этой проблеммы с использованием CompiledQuery, но с очень большим гемороем, так что даже рассказывать не хочется

У меня данный отбор стоит в основе всего запроса и мне очень критична скорость потому-что запрос получается очень большим.
Можете что-нибудь посоветовать по этому поводу.
Так чтоб это можно было вставить в CompiledQuery.
Re[4]: CompiledQuery
От: Curufinwe Украина  
Дата: 05.03.08 16:31
Оценка:
Здравствуйте, fabio, Вы писали:

F>У меня данный отбор стоит в основе всего запроса и мне очень критична скорость потому-что запрос получается очень большим.

F>Можете что-нибудь посоветовать по этому поводу.
F>Так чтоб это можно было вставить в CompiledQuery.

Я бы всё-таки посоветовал сначала протестировать скорость работы Linq без CompiledQuery и просто идентичного SQL запроса. Если разница в разы, а построить SQL вручную очень сложно, то может и стоит рассматривать то "полурешение".

Вкратце смысл следующий:
В полуавтоматическом режиме преобразовываем linq expression wr=>list.Contains(wr.ID) в wr=> wr.ID == id1 || wr.ID == id2 || и т.д. (т.е. работать придётся напрямую с linq выражением).
Далее для каждого размера массива компилируется свой Linq запрос (поэтому если рамеры массива могуть быть большими > 10, то этот подход вообще не имеет смысла). Получается, что для каждого размера массива производится только одна компиляция.

Если этот подход всё-таки вас заинтересует, то возможно позже я смогу выслать какие-то примеры кода. Сейчас просто вдаватся в подробности нет времени.
... << RSDN@Home 1.2.0 alpha rev. 693>>
Re[5]: CompiledQuery
От: fabio Узбекистан  
Дата: 06.03.08 09:33
Оценка:
Здравствуйте, Curufinwe, Вы писали:

C>Я бы всё-таки посоветовал сначала протестировать скорость работы Linq без CompiledQuery и просто идентичного SQL запроса. Если разница в разы, а построить SQL вручную очень сложно, то может и стоит рассматривать то "полурешение".


C>Вкратце смысл следующий:

C>В полуавтоматическом режиме преобразовываем linq expression wr=>list.Contains(wr.ID) в wr=> wr.ID == id1 || wr.ID == id2 || и т.д. (т.е. работать придётся напрямую с linq выражением).
C>Далее для каждого размера массива компилируется свой Linq запрос (поэтому если рамеры массива могуть быть большими > 10, то этот подход вообще не имеет смысла). Получается, что для каждого размера массива производится только одна компиляция.

C>Если этот подход всё-таки вас заинтересует, то возможно позже я смогу выслать какие-то примеры кода. Сейчас просто вдаватся в подробности нет времени.


Я произвел замеры и примерно скорость измеряется в пределах 2-10 (от сложности запроса с полученными данными после второй фильтрации)(это условия применяется только во второй фильтрации).

Думаю надо включать полушарие.

Думаю идея linq expression wr=>list.Contains(wr.ID) в wr=> wr.ID == id1 || wr.ID == id2 || --> не очень подходит.
Re: CompiledQuery
От: pr0ff  
Дата: 10.03.08 08:54
Оценка:
Здравствуйте, fabio, Вы писали:
F>то он ругается, что объекты из другого контекста и это не поддерживается Linq to SQL.
            public void Detach()
            {
                _category = default(EntityRef<Category>);
                _items = default(EntitySet<Item>);
                // и т.д. для всех EntityRef и EntitySet
            }

После вызова этого метода, объект готов к привязке к другому контексту.
P.S. после этого работать со старым контекстом не рекомендуется — хз как он себя поведет.
... << RSDN@Home 1.2.0 alpha 2 rev. 852>>
Re[2]: CompiledQuery
От: pr0ff  
Дата: 10.03.08 09:06
Оценка:
Здравствуйте, fabio, Вы писали:
F>Может кто-нибудь уже пробовал? Помогите.
Не пробовал.
Вызывайте DataContext.GetCommand(query), а дальше компилируйте команду методом Prepare, меняйте значения параметров, получайте DataReader и передавайте его методу DataContext.Translate. Будет работать только с таким же кол-вом элементов (как и любой другой вариант).
... << RSDN@Home 1.2.0 alpha 2 rev. 852>>
Re[3]: CompiledQuery
От: pr0ff  
Дата: 10.03.08 09:14
Оценка:
Или же можно попробовать массив передать в троке, а на сервере через хранимку или функцию преобразовать эту строку в таблицу. Правда хз будет ли быстрее.
... << RSDN@Home 1.2.0 alpha 2 rev. 852>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.