Entity Framework: «Оператор сохранения, вставки или удаления затронул неожиданное количество строк (0)». [закрыто]


324

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

Оператор хранения, обновления или удаления затронул неожиданное количество строк (0). Объекты могут быть изменены или удалены с момента загрузки объектов. Обновите записи ObjectStateManager.

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

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


Я получил эту ошибку с введением политики безопасности на уровне строк в SQL Server, которая позволяла обновлять строки в состоянии, которое невозможно прочитать (эксклюзивный предикат FILTER с разрешающим предикатом BLOCK) . EntityFramework требует, чтобы обновленная строка читалась обратно после обновления, в противном случае предполагается, что это была ошибка параллелизма (по крайней мере, при использовании оптимистичного параллелизма).
xr280xr

Проблема может быть в неправильной области видимости для вашего DBContext stackoverflow.com/questions/49154250/… (этот пример относится к удостоверению ASPNET, но применяется для любого контекста)
Simon_Weaver

Независимо от контекста этой ошибки, хорошей идеей будет установить точку останова, где бы он ни создавался. Вы ожидали, что он будет создан один раз, когда вы загрузили веб-страницу, но она достигает этой точки останова 5 раз? Тогда у вас, вероятно, есть состояние гонки. Посмотрите на Request.Uriфактический URL запроса. В моем случае у меня была некоторая логика отслеживания, которая поражала мой сайт и излишне загружала контекст из БД (и иногда обновляла его тоже). Таким образом, на реальной странице, которую я отлаживал, были растоптаны данные с помощью глупой логики кода отслеживания.
Simon_Weaver

add @ Html.AntiForgeryToken () в поле зрения
Викас Шарма

Ответы:


199

Это побочный эффект функции, называемой оптимистичным параллелизмом.

Не уверен на 100%, как включить / выключить его в Entity Framework, но в основном он говорит вам о том, что между моментом, когда вы извлекли данные из базы данных, и когда вы сохранили свои изменения, кто-то другой изменил данные (что означало, что вы пошли чтобы сохранить его, 0 строк были обновлены). В терминах SQL предложение их updateзапроса whereсодержит исходное значение каждого поля в строке, и, если затронуто 0 строк, он знает, что что-то пошло не так.

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

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


34
Это происходит в однопользовательской среде (на моей машине разработчика), поэтому я не думаю, что это может быть условием гонки. Я привязываюсь к пользовательскому элементу управления сеткой с помощью EntityDataSource, поэтому я не уверен, что именно происходит за кулисами, но у меня нет собственного дополнительного кода, который модифицирует таблицы. Есть ли способ изменить этот параметр параллелизма?
strongopinions

3
Я думаю, что вы можете сделать это для каждой колонки в вашей модели сущности (она находится в окне свойств), но дело в том, что вы просто не увидите ошибку и ничего не обновите. Можете ли вы просматривать команды SQL, поступающие в вашу базу данных (например, SQL Server Profiler для MSSQL)? Таким образом, вы сможете увидеть, какое обновление оно генерирует, и понять, почему это обновление не влияет на строки.
Fyjham

9
Если у объекта есть свойство timestamp, убедитесь, что оно хранится в вашем представлении, и убедитесь, что объект правильно заполняет отметку времени.
2013 года

У меня был столбец меток времени, и как только я обратился к нему, EF6.1 заработал, как и ожидалось, спасибо за подсказку @anelBMer
JQII

3
Если вы используете временные метки, то объекту, который вы хотите удалить, требуется набор PK и свойство RowVersion для его успешного обновления! Я устанавливал свойство rowVersion (timestamp) после того, как я прикрепил объект к соответствующему DbSet, поэтому он не работал. Хорошая работа!
Легенды

394

Я столкнулся с этим, и это было вызвано тем, что поле ID (ключ) сущности не было установлено. Таким образом, когда контекст пошел на сохранение данных, он не смог найти ID = 0. Обязательно поместите точку останова в операторе обновления и убедитесь, что идентификатор сущности установлен.

Из комментария Пола Беллора

У меня была именно эта проблема, вызванная забыванием включить скрытый ввод идентификатора на страницу редактирования .cshtml


3
+1 У меня была такая же проблема, и это помогло найти решение. Оказывается, в моей модели Order было [Bind (Exclude = "OrderID")], в результате чего значение идентификатора сущности было равно нулю на HttpPost.
Dhaust

2
Это именно то, чего мне не хватало. Идентификатор моего объекта был 0.
Азхар Хорасаны

4
@ Html.HiddenFor (model => model.productID) - работает отлично. Я пропустил productID на странице редактирования (бритва MVC)
Рави Рам

2
У меня была похожая проблема, но с изюминкой. Для меня проблема заключалась в том, что я не правильно настроил таблицу sql. Мое поле первичного ключа не было установлено с автоматическим приращением. Таким образом, EF отправит запись, которую я пытался вставить без ключа, и это хорошо, если вы не забудете сообщить sql, что это поле с автоматическим приращением, которое я забыл: <
Agile Noob

1
Та же проблема, но с использованием составного ключа. Одно из ключевых значений не было установлено.
Обайлись

113

Вау, много ответов, но я получил эту ошибку, когда сделал что-то немного другое, о чем не упоминал ни один другой.

Короче говоря, если вы создадите новый объект и скажите EF, что он был изменен с использованием, EntityState.Modifiedто он выдаст эту ошибку, так как он еще не существует в базе данных. Вот мой код:

MyObject foo = new MyObject()
{
    someAttribute = someValue
};

context.Entry(foo).State = EntityState.Modified;
context.SaveChanges();

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

Легко исправить, просто изменить EntityState.Modifiedк EntityState.Addedили изменить , что вся линия:

context.MyObject.Add(foo);

Спасибо за публикацию этого. Это тоже была моя проблема, я скопировал некоторый код, который устанавливал State в EntityState.Modified.
clayRay

23

Я столкнулся с той же самой страшной ошибкой ... :) Потом я понял, что забыл установить

@Html.HiddenFor(model => model.UserProfile.UserId)

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

Кстати: HiddenForэто для ASP.NET MVC.


3
Это похоже на недостаток безопасности, чтобы хранить UserIdв форме, очень склонной к хакерам ... это должно быть заполнено впоследствии изHttpContext.Current.User.Identity.Name
Серж Саган

@SerjSagan вы правы ... но пока вы делаете некоторые проверки на стороне сервера, чтобы подтвердить UserId и текущее имя пользователя, вы готовы идти.
Лениэль Маккаферри

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

16

Проверьте, не забыли ли вы атрибут «DataKeyNames» в GridView. это необходимо при изменении данных в GridView

http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.datakeynames.aspx


+1. Идеальное и простое решение для меня. Я связываю GridView с EntityDataSource и не установил это в качестве моего первичного ключа на объекте.
Андез

Мы знаем, что пользовательский интерфейс Kendo не поддерживает составной ключ, но если я добавлю новый столбец, в котором мои ключи совпадают с одним, что происходит тогда?
Бранислав

15

Проблема вызвана одной из двух причин:

  1. Вы попытались обновить строку с одним или несколькими свойствами Concurrency Mode: Fixed.. и оптимистический параллелизм не позволил сохранить данные. То есть. некоторые изменяли данные строки между временем получения вами данных сервера и сохранением данных вашего сервера.
  2. Вы пытались обновить или удалить строку, но эта строка не существует. Другой пример того, как кто-то изменяет данные (в данном случае, удаляет) между извлечением, а затем сохранением ИЛИ, если вы пытаетесь обновить поле, которое не является идентификатором (т.е. StoreGeneratedPattern = Computed), и эта строка не существует.

1
Это также может быть вызвано тем, что все свойства объекта, которые были назначены, им были присвоены те же значения, что и раньше.
Серж Саган

+1 за 2й. У меня StoreGeneratedPattern = None, меняя на StoreGeneratedPattern = Identity решил проблему. Спасибо
tkt986

12

Я получил эту же ошибку, потому что часть PK была столбцом datetime, а вставляемая запись использовала DateTime.Now в качестве значения для этого столбца. Платформа сущностей будет вставлять значение с точностью до миллисекунды, а затем искать только что вставленное значение с точностью до миллисекунды. Однако SqlServer округлил значение до второй точности, и, таким образом, объектная структура не смогла найти значение с точностью до миллисекунды.

Решение было обрезать миллисекунды от DateTime.Now перед вставкой.


2
У нас была та же проблема, за исключением того, что мы вставляли в Dateстолбец со DateTimeзначением
adam0101

1
Тоже самое. У нас была запись в хранилище данных, и мы использовали временную метку как часть ключа. Отметка времени в хранилище данных была SQL DateTime, но отметка времени в C # не совпадала. Я изменил тип данных SQL на DateTime2 (7), обновил модель EF, и все было исправлено.
mmcfly

Изменение столбца на Datetime2 (7) работало и для меня. Спасибо @mmcfly
Dzejms

10

У меня возникла та же проблема, и ответ @ webtrifusion помог найти решение.

Моя модель использовала Bind(Exclude)атрибут идентификатора сущности, что приводило к тому, что значение идентификатора сущности было нулевым на HttpPost.

namespace OrderUp.Models
{
[Bind(Exclude = "OrderID")]
public class Order
{
    [ScaffoldColumn(false)]
    public int OrderID { get; set; }

    [ScaffoldColumn(false)]
    public System.DateTime OrderDate { get; set; }

    [Required(ErrorMessage = "Name is required")]
    public string Username { get; set; }
    }
}   

Подобная проблема, в целях безопасности, у меня есть Bind (include = некоторые поля). ID не было в списке. Также я добавил это как скрытый вход. Должно быть, стерто что-то, сгенерированное MVC, или ID вообще не было. Спасибо за помощь.
MusicAndCode

10

У меня была та же проблема, я выяснил, что это было вызвано RowVersion, который был нулевым. Убедитесь, что ваш Id и RowVersion не равны NULL .

для получения дополнительной информации обратитесь к этому руководству

http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application


версия строки в моем случае была нулевой
Пракаш

В моем случае я случайно удалил поле Id в моем [Bind (Include = properties)]. Добавьте его обратно, и он работал нормально.
Caverman

8

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

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

using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;

public class MyDbContext: DbContext {
...
        public int SaveChanges(bool refreshOnConcurrencyException, RefreshMode refreshMode = RefreshMode.ClientWins) {
            try {
                return SaveChanges();
            }
            catch (DbUpdateConcurrencyException ex) {
                foreach (DbEntityEntry entry in ex.Entries) {
                    if (refreshMode == RefreshMode.ClientWins)
                        entry.OriginalValues.SetValues(entry.GetDatabaseValues());
                    else
                        entry.Reload();
                }
                return SaveChanges();
            }
        }
}

Затем вызывается, SaveChanges(true)где это применимо.


1
Хорошо, все остальные жалуются на проблему, показывают, как они могут ее вызвать и т. Д., Но этот ответ имеет крутой ответ. Я использую модель продолжения обновления (здесь нет кнопки сохранения, детка), и получал это при обновлениях сетки, когда поток EF отставал, и решил это. Блестящая работа, мое доброе имя .. ты заставил меня выглядеть как герой - стоя на плече гигантов !!
Тони Трембат-Дрейк

Мне тоже помогли, посмотрите на это для получения дополнительных опций
Цви

7

Вам необходимо явно включить BoundField первичного ключа. Если вы не хотите, чтобы пользователь видел первичный ключ, вы должны скрыть его с помощью css:

    <asp:BoundField DataField="Id_primary_key" ItemStyle-CssClass="hidden" 
HeaderStyle-CssClass="hidden" />

Где «скрытый» - это класс в css, для которого установлено отображение «нет».


1
хах, вы поняли, что я удалил свое скрытое поле id в ASP.NET MVC. Спасибо @ Пауло! :)
Томаш Иневич

7

При редактировании включите идентификатор или первичный ключ объекта в качестве скрытого поля в представлении.

т.е.

      @Html.HiddenFor(m => m.Id)

это решает проблему.

Также, если ваша модель содержит неиспользуемый элемент, включите его и отправьте на контроллер


7

Я тоже сталкивался с этой ошибкой. Проблема оказалась вызвана триггером на столе, к которому я пытался сохранить. Триггер использовал «INSTEAD OF INSERT», что означает, что 0 строк когда-либо вставлялось в эту таблицу, следовательно, ошибка. К счастью, в некоторых случаях функциональность триггера была неправильной, но я предполагаю, что это может быть допустимой операцией, которая должна каким-то образом обрабатываться в коде. Надеюсь, это поможет кому-нибудь однажды.


2
Сущность можно обмануть, поверив, что строки были добавлены путем возврата оператора SELECT (со столбцом первичного ключа) из триггера.
Джаху

1
Чтобы расширить комментарий @jahu, мне нужно было получить фактический идентификатор вновь вставленного элемента, который должен быть возвращен из моего триггера, а имя столбца должно соответствовать столбцу идентификаторов таблицы триггера (в моем случае, фактически это представление, так что У меня нет собственной идентичности, но я обманул edmx, заставив поверить в это. Мой триггер делал вставку в отдельную таблицу, поэтому я просто добавил эту последнюю строку в свой триггер:SELECT SCOPE_IDENTITY() as MyViewId
DannyMeister

Также смотрите этот вопрос: stackoverflow.com/questions/5820992/…
J. Polfer

В моем случае я выполнял операцию удаления сущностей в дочерней коллекции, но был один из триггеров на удаление для одной из дочерних сущностей, которая вызывала удаление другой из дочерних сущностей. Это вызвало ошибку, поскольку было затронуто N - 1 строк из-за триггера, удаляющего одну из дочерних сущностей до того, как структура сущностей попыталась удалить ее.
скелетбанк

6

Я столкнулся с этой проблемой в таблице, в которой отсутствовал первичный ключ и имел столбец DATETIME (2, 3) (поэтому «первичный ключ» сущности представлял собой комбинацию всех столбцов) ... При выполнении вставки метка времени имела более точное время (2018-03-20 08: 29: 51.8319154), которое было усечено до (2018-03-20 08: 29: 51.832), поэтому поиск по ключевым полям не удался.


5

У меня тоже была эта ошибка. В некоторых ситуациях сущность может не знать о фактическом контексте базы данных, который вы используете, или модель может отличаться. Для этого установите: EntityState.Modified; в EntityState.Added;

Сделать это:

if (ModelState.IsValid)
{
context.Entry(yourModelReference).State = EntityState.Added;
context.SaveChanges();
}

Это гарантирует, что Организация знает, что вы используете или добавляете штат, с которым вы работаете. На этом этапе все правильные значения модели должны быть установлены. Будьте осторожны, чтобы не потерять какие-либо изменения, которые могли быть сделаны в фоновом режиме.

Надеюсь это поможет.


1
ты гуру! это работает для меня!
Эрнальдо Гонсалес

5
  @Html.HiddenFor(model => model.RowVersion)

Моя версия строки была нулевой, поэтому пришлось добавить это к представлению, которое решило мою проблему


Не передавал RowVersion из View в действие редактирования, плюс я забыл сделать привязку модели для RowVersion. Когда вы сохраняете объект в БД, вам нужно, чтобы предыдущее значение RowVersion было отправлено в БД вместе с объектом для проверки параллелизма. Вы делаете глупые ошибки, когда вам нужны вещи быстрее!
Dhanuka777

5

Линия [DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.None)]добилась цели в моем случае:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;


[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int? SomeNumber { get; set; }

4

Просто убедитесь, что таблица и форма имеют первичный ключ и edmx обновлены.

я обнаружил, что любые ошибки во время обновления обычно были из-за: - Нет первичного ключа в таблице - Нет первичного ключа в представлении / форме редактирования (например @Html.HiddenFor(m=>m.Id)


4

У меня такая же проблема. В моем случае я пытался обновить первичный ключ, что не разрешено.


4

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

Ошибки время от времени:

[Authorize(Roles = "Admin")]
[HttpDelete]
[Route("file/{id}/{customerId}/")]
public async Task<IHttpActionResult> Delete(int id, int customerId)
{
    var file = new Models.File() { Id = id, CustomerId = customerId };
    db.Files.Attach(file);
    db.Files.Remove(file);

    await db.SaveChangesAsync();

    return Ok();
}

Работает все время:

[Authorize(Roles = "Admin")]
[HttpDelete]
[Route("file/{id}/{customerId}/")]
public IHttpActionResult Delete(int id, int customerId)
{
    var file = new Models.File() { Id = id, CustomerId = customerId };
    db.Files.Attach(file);
    db.Files.Remove(file);

    db.SaveChanges();

    return Ok();
}

Хотя это решило мою проблему, это послужило указанием на основную проблему, упомянутую ранее в этом посте о версиях PK и Row. Я забыл добавить карту схемы для новой таблицы, что еще более усложнилось тем, что PK не следовал правилу именования. <Имя таблицы> ID.
midohioboarder

3

Я получил эту ошибку, когда удалял несколько строк в БД (в цикле) и добавлял новые в той же таблице.

Решением для меня было динамическое создание нового контекста в каждой итерации цикла


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

3
    public void Save(object entity)
    {
        using (var transaction = Connection.BeginTransaction())
        {
        try
                {
                    SaveChanges();
                    transaction.Commit();
                }
                catch (OptimisticConcurrencyException)
                {
                    if (ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Deleted || ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Modified)
                        this.Refresh(RefreshMode.StoreWins, entity);
                    else if (ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Added)
                        Detach(entity);
                    AcceptAllChanges(); 
                    transaction.Commit();
                }
        }
    }

Не могли бы вы уточнить, на что здесь ссылается «это» и что такое ObjectStateManager? Я пытаюсь сделать это в нашем базовом классе репозитория, но получаю ошибки
Наоми

3

Это также произойдет, если вы пытаетесь вставить в уникальную ситуацию ограничения, то есть, если у вас может быть только один тип адреса на одного работодателя, и вы пытаетесь вставить секунду того же типа с тем же работодателем, вы получите ту же проблему ,

ИЛИ

Это также может произойти, если все свойства объекта, которые были назначены, им были присвоены те же значения, что и раньше.

        using(var db = new MyContext())
        {
            var address = db.Addresses.FirstOrDefault(x => x.Id == Id);

            address.StreetAddress = StreetAddress; // if you are assigning   
            address.City = City;                   // all of the same values
            address.State = State;                 // as they are
            address.ZipCode = ZipCode;             // in the database    

            db.SaveChanges();           // Then this will throw that exception
        }

2

Если вы пытаетесь создать сопоставление в своем файле edmx с функцией «Импорт», это может привести к этой ошибке. Просто очистите поля для вставки, обновления и удаления, которые находятся в Mapping Details для данного объекта в вашем edmx, и это должно работать. Надеюсь, я дал понять.


2

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

context.Users.Attach(orderer);

с участием

if (orderer.Id > 0) {
    context.Users.Attach(orderer);
}

2

Ну, у меня есть такая же проблема. Но это было из-за моей собственной ошибки. На самом деле я сохранял объект вместо того, чтобы добавить его. Так что это был конфликт.


2

Одним из способов решения этой проблемы в среде сервера Sql является использование Sql Profiler, включенного в вашу копию SqlServer, или, если вы используете версию Express, получите бесплатную копию Express Profiler из CodePlex по следующей ссылке:

Экспресс Профилировщик

Используя Sql Profiler, вы можете получить доступ ко всему, что отправляет EF в БД. В моем случае это составило:

exec sp_executesql N'UPDATE [dbo].[Category]
SET [ParentID] = @0, [1048] = NULL, [1033] = @1, [MemberID] = @2, [AddedOn] = @3
WHERE ([CategoryID] = @4)
',N'@0 uniqueidentifier,@1 nvarchar(50),@2 uniqueidentifier,@3 datetime2(7),@4 uniqueidentifier',
@0='E060F2CA-433A-46A7-86BD-80CD165F5023',@1=N'I-Like-Noodles-Do-You',@2='EEDF2C83-2123-4B1C-BF8D-BE2D2FA26D09',
@3='2014-01-29 15:30:27.0435565',@4='3410FD1E-1C76-4D71-B08E-73849838F778'
go

Я скопировал вставил это в окно запроса в Sql Server и выполнил его. Конечно, несмотря на то, что он выполнялся, на 0 записей повлиял этот запрос, поэтому EF вернула ошибку.

В моем случае проблема была вызвана CategoryID.

Не было идентификатора категории, идентифицированного идентификатором EF, отправленным в базу данных, следовательно, затронуто 0 записей.

Это была не ошибка EF, а скорее глючная нуль-слияние "??" утверждение в контроллере представления, который отправлял ерунду на уровень данных.


2

Ни один из приведенных выше ответов не вполне охватил мою ситуацию и ее решение.

Код, в котором была выдана ошибка в контроллере MVC5:

        if (ModelState.IsValid)
        {
            db.Entry(object).State = EntityState.Modified; 
            db.SaveChanges(); // line that threw exception
            return RedirectToAction("Index");
        }

Я получил это исключение, когда я сохранял объект из представления редактирования. Это вызвано тем, что когда я вернулся, чтобы сохранить его, я изменил свойства, которые сформировали первичный ключ объекта. Таким образом, установка его состояния на Modified не имеет никакого смысла для EF - это была новая запись, а не ранее сохраненная.

Вы можете решить это, либо A) изменив вызов save для добавления объекта, либо B) просто не изменив первичный ключ при редактировании. Я сделал б).


2

Когда принятый ответ сказал: « Это не приведет к перезаписи изменения, о котором ваше приложение не знает », я скептически отнесся к тому, что мой объект был недавно создан. Но затем выясняется, что INSTEAD OF UPDATE, INSERT- TRIGGERк таблице была прикреплена таблица, которая обновляла вычисляемый столбец этой же таблицы.

Как только я изменил это на AFTER INSERT, UPDATE, все работало нормально.


2

Это произошло со мной из-за несоответствия между datetime и datetime2. Странно, он работал нормально до того, как тестер обнаружил проблему. Моя модель Code First включала DateTime как часть первичного ключа:

[Key, Column(Order = 2)]  
public DateTime PurchasedDate { get; set; } = (DateTime)SqlDateTime.MinValue;

Созданный столбец является столбцом даты и времени. При вызове SaveChanges EF генерирует следующий SQL:

-- Region Parameters
DECLARE @0 Int = 2
DECLARE @1 Int = 25
DECLARE @2 Int = 141051
DECLARE @3 DateTime2 = '2017-07-27 15:16:09.2630000' --(will not equal a datetime value)
-- EndRegion
UPDATE [dbo].[OrganizationSurvey]
SET [OrganizationSurveyStatusId] = @0
WHERE ((([SurveyID] = @1) AND ([OrganizationID] = @2)) AND ([PurchasedDate] = @3))

Поскольку он пытался сопоставить столбец datetime со значением datetime2, он не дал результатов. Единственное решение, о котором я мог подумать, это изменить столбец на datetime2:

[Key, Column(Order = 2, TypeName = "DateTime2")]  
public DateTime PurchasedDate { get; set; } = (DateTime)SqlDateTime.MinValue;

1
Странность того, что он работает против не работает, связана с базовым форматом / базой datetimeпротив datetime2. По существу, некоторые значения в миллисекундах будут соответствовать друг другу, другие - нет. То же самое случилось со мной, и я тоже переключился на DateTime2.
xr280xr

+1 Я хотел бы +100 на этом для вас. После осмотра многих мест я, наконец, нашел это и понял, что действительно у меня есть Datetime как часть моего первичного ключа. Да, это действительно исправило это. Я обновил столбец до Datetime2, и это сработало. Теперь моя претензия к Entity Framework за разработку такого дерьмового запроса для этого, который заставляет меня делать это.
Catchops
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.