Entity Framework не обновляет значение, которое изменяется триггером
мой стол Sections
(SQL Server) имеет ID
в качестве первичного ключа (int, identity)
и SortIndex
столбец (int) для целей сортировки.
база данных имеет триггер, который устанавливает SortIndex := ID
в каждом INSERT
. Очевидно, я хочу изменить индекс сортировки позже, поменяв значения для двух строк.
я получаю доступ к данным с помощью Entity Framework, все с веб-приложением MVC3.
проблема в том, что Entity Framework не обновляет значение SortIndex
после I вставить новый объект в таблицу. Он также кэширует все данные, поэтому следующий вызов для получения всех объектов из этой таблицы также даст неправильный SortIndex
значение для этого объекта.
я пытался менять StoreGeneratedPattern
для этой колонки в EDMX
. Это кажется большим и элегантным, но не решает проблему.
если я Identity
, это заставляет EF правильно обновлять значение, но оно становится только для чтения (исключение, возникающее при попытке изменить). Установка его в Computed
is аналогично, но вместо исключения значения просто не записываются в БД.
я могу воссоздать объект EF каждый раз, если мне нужно использовать его после вставки объекта, просто выполнив:
DatabaseEntities db = new DatabaseEntities()
но для меня это кажется уродливым обходным путем.
каково решение этой проблемы?
очевидно, что-то, что не требует от меня делать некоторые действия после каждого insert
(и рискните, что это забыто и незамечено) предпочтительный.
3 ответов
короче StoreGeneratedPattern
означает: значение обрабатывается магазином, и ваше приложение никогда не изменит его. В таком случае вы получите автоматически сгенерированное значение магазина после вызова SaveChanges
.
если вы не используете StoreGeneratedPattern
вы не получите значение, и вам придется принудительно выполнить другой запрос для обновления вашей сущности. Вы можете, например, сделать:
objectContext.Refresh(RefreshMode.StoreWins, yourSection);
обычно ситуации, когда вам нужно обновить значения в обеих базах данных с помощью триггеров и приложений не играйте очень хорошо с EF (и, вероятно, другими инструментами ORM).
я нашел ответ от "Ладислава Мрнка" точным и отметил его как принятый. Вот другие обходные пути, которые я нашел, пытаясь найти какое-то решение. Однако решение, которое я искал, вообще невозможно.
одна из возможностей-установить StoreGeneratedPattern = Computed
чтобы сообщить EF, это значение вычисляется. А затем сделайте хранимую процедуру, чтобы фактически изменить значение SortIndex
. Обычно он меняет значения в двух строках (меняет их местами), чтобы изменить сортировку порядок. Эта процедура вместе с триггером at INSERT
дает гарантию, что данные остаются согласованными в БД. Невозможно создать новую строку без правильного значения, установленного в SortIndex
, невозможно сделать два объекта с одинаковым значением (если хранимая процедура не имеет ошибки), и невозможно каким-то образом вручную разбить значение, потому что невозможно редактировать через EF. Похоже, отличное решение.
легко возможно иметь хранимые процедуры, сопоставленные с функциями в ФВ.
проблема в том, что теперь можно ввести новую строку и EF правильно обновляет данные в своем кэше, но кэш не обновляется после вызова хранимой процедуры. Еще нужен ручной функция обновления или обновления. В противном случае следующий вызов для получения объектов, отсортированных по SortIndex
даст неправильные результаты.
кроме этого, можно установить MergeOption = MergeOption.OverwriteChanges
для нескольких объектов, что заставляет EF обновлять данные из БД несколько лучше. С этого делается, можно перечитать объект после его вставки или вызова хранимой процедуры, и он будет обновлен. Однако чтение коллекции объектов с помощью db.Section.OrderBy(o => o.SortIndex)
по-прежнему будет возвращать кэшированные результаты с неправильным порядком сортировки.
если кто-то заинтересован, это можно сделать MergeOption
по умолчанию к чему-то еще, добавив частичный класс EF, а затем частичный метод OnContextCreated
, как здесь:
public partial class DatabaseEntities
{
partial void OnContextCreated()
{
Subsection.MergeOption = MergeOption.OverwriteChanges;
Section.MergeOption = MergeOption.OverwriteChanges;
Function.MergeOption = MergeOption.OverwriteChanges;
}
}
вы знаете, будете ли вы работать с этой колонкой снова в том же запросе?
Я бы использовал контекст для сценария запроса, который обычно избавляет вас от многих проблем, потому что новый контекст EF создается с каждым запросом, поэтому у вас есть свежие данные один раз за запрос.
с длинными жил контекста, там может вырасти incosistencies как вы описали.
в любом случае StoreGeneratedPattern, установленный на вычисляемый, должен быть прав. Но он обновляется только тогда, когда вы храните фактическую сущность. Он не обновляется путем вставки или обновления какой-либо другой сущности.
от http://msdn.microsoft.com/en-us/library/dd296755 (v=против 90).aspx
при создании нового объекта или изменении существующего объекта значения свойств с параметром StoreGeneratedPattern, равным Computed, извлекаются с сервера при вызове метода SaveChanges в приложении. Если присвоить значение свойству с помощью StoreGeneratedPattern значение вычисляется в приложении, значение будет перезаписано значением, сгенерированным сервером при вызове метода SaveChanges.
мы используем параметр вычисляемого значения для SQL sequenced GUID, и он работает нормально.