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, и он работает нормально.