Переопределение поведения кэширования / отслеживания изменений в Linq to SQL - PullRequest
1 голос
/ 02 февраля 2010

Я думаю, что, возможно, первоначальный вопрос был слишком многословным и содержал слишком много ненужных деталей, поэтому это моя попытка упрощения.

Я ищу способ выполнить любое из приведенных ниже действий. Мне нужно сделать только один, а не все. Если кто-нибудь знает ответ хотя бы на один из них, ответьте. Итак, возможно ли выполнить одно из следующих действий в Linq to SQL:

  • Извлечение сущностей из DataContext через ExecuteQuery или ExecuteMethodCall без отслеживания этих сущностей?

  • Вызвать ExecuteQuery или ExecuteMethodCall и гарантировать, что я всегда получаю свежие копии результатов, извлеченных из базы данных, даже если эти объекты уже были извлечены и уже находятся в кэше идентификации?

  • Поручить Linq to SQL не выполнять никакого отслеживания изменений каких-либо конкретных типов объектов - но все же разрешать отслеживание изменений для других типов?

Ограничения:

  • Метод Refresh исключен; количество объектов достаточно велико, и это может привести к падению производительности.

  • Я не могу просто установить ObjectTrackingEnabled на false, потому что DataContext не позволяет установить его обратно на true после выполнения запроса, и мне нужно немного объектов для отслеживания.

  • Я также не могу выбросить оригинал DataContext и использовать новый; Я должен быть в состоянии сделать это в середине транзакции.


Это начинает становиться серьезной проблемой, и я действительно думаю, что поведение по умолчанию является непродуманным. Если я выполню специальный запрос или хранимую процедуру, я ожидаю, что результаты, которые я получу, будут точными результатами, которые были возвращены этим запросом. Это имеет смысл только; если мне нужны старые, устаревшие сущности, зачем мне возвращаться в базу данных, чтобы получить их?

В настоящее время мой обходной путь - либо (а) создать новый DataContext специально для запроса и переопределить уровень изоляции транзакции, либо (б) сделать тип возвращаемого значения "DTO", идентичным сущности любым способом, но без атрибута [Table], и сопоставьте его с исходной сущностью, используя AutoMapper. Оба они кажутся ужасными взломами.

Буду очень признателен за любые предложения по этой головоломке.

Ответы [ 2 ]

3 голосов
/ 05 февраля 2010

Мне удалось найти жизнеспособный долгосрочный обходной путь для этой проблемы. Это не совсем идеально, но до сих пор это было относительно безболезненно и гораздо менее страшно, чем альтернативы.

Так как эти запросы в любом случае являются чистым SQL - они все ExecuteQuery для встроенного SQL или ExecuteMethodCall для хранимых процедур - я решил просто перейти к «сырому» ADO.NET для случаев, когда я не Я не хочу, чтобы DataContext знал о некоторых сущностях.

Конечно, было бы ужасно иметь дело с кучей IDbCommand экземпляров и ручных отображений из IDataReader, поэтому я потратил несколько часов этим утром на кодирование библиотеки, чтобы выполнить большую часть тяжелой работы для меня, выставив «свободно» (я использую термин «свободно») оболочку для IDbCommand, автоматический LinqDataReaderMapper, который использует MetaModel, чтобы я мог использовать свои существующие сущности без изменений, и кучу перегруженных методов расширения для ускорить написание простых запросов.

В конце дня я пишу что-то вроде этого:

var results = context.Connection
    .Command("SELECT Column1, Column2 FROM Table " +
             "WHERE FilterColumn1 = @Param1 AND FilterColumn2 = @Param2")
    .Parameters(
        p => p.Name("Param1").Value(someValue),
        p => p.Name("Param2").Value(someOtherValue))
    .ExecuteReader()
    .MapWith(context.Mapping).To<MyEntity>();

Или просто так:

var results = context
    .ExecuteQueryRaw<MyEntity>(CommandType.StoredProcedure, "SomeProc",
        new { Param1 = someValue, Param2 = someOtherValue });

Я не собираюсь публиковать весь код для него - он довольно длинный, и я думаю, что это будет просто большой tl; dr на данный момент - но основная идея заключается в том, что оба они дают я возвращаю IEnumerable<MyEntity>, и, поскольку они копируются непосредственно из IDataReader, они по сути являются отдельными объектами - DataContext не имеет прямого представления о них и поэтому не может ни перехватывать результаты, ни отслеживать их после факта .

Итак, проблема частично решена, хотя было бы лучше, если бы я мог заставить DataContext вести себя сам.

0 голосов
/ 06 февраля 2010

Если вы создаете новый объект для ваших результатов из запроса LINQ, он не будет отслеживаться.Таким образом, вы можете использовать свой существующий DataContext для загрузки значений, которые, как вы знаете, вам не нужно обновлять, например, так (код здесь ):

using (NorthwindDataContext context = new NorthwindDataContext())
{
  var a = from c in context.Categories
  select new Category
  {
    CategoryID = c.CategoryID,
    CategoryName = c.CategoryName,
    Description = c.Description
  };
}

Я думаю, что это по сути то, что выво втором примере в вашем ответе, я просто хочу подтвердить, что это работает и не является плохой идеей.

Кроме того, я понимаю, что вы не должны использовать ни одного массивного DataContext в любом случае;DataContext - это на самом деле коллекция уровня единицы работы, а не весь мир.Таким образом, использование отдельных DataContexts для данных типа «только для чтения» и ваших обновляемых данных имеет смысл (если вы не можете предсказать, что именно заранее, я полагаю).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...