Entity Framework 6.0 Code first — получение повторяющихся элементов в простом запросе при фильтрации по первичному ключу

В моем проекте мы используем EF Code First (v.6.0.0.0) и MS SQL Server 2012.

Я обновился до Entity Framework до 6-й версии. Странно, что в какой-то момент после обновления у меня стали появляться дубликаты при фильтрации записей по первичному ключу.

Прежде всего, я начал получать исключение «Последовательность содержит более одного элемента» в следующем коде.

var cateringService = context.CateringServices
                             .SingleOrDefault(x => x.Id == query.CateringServiceId)

Я проверил базу данных и параметр - Id является первичным ключом, он помечен как уникальный, и параметр был допустимым. Поскольку Id был установлен в качестве первичного ключа в сопоставлении:

this.HasKey(x => x.Id);

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

var cateringServices = context.CateringServices
                              .Where(x => x.Id == query.CateringServiceId)
                              .ToList();

Казалось, что я получаю 13 экземпляров сущности «CateringService», ссылающихся на одну и ту же строку. Пожалуйста, посмотрите на прикрепленные скриншоты:

введите здесь описание изображениявведите здесь описание изображения

Кроме того, я начал получать исключение A relationship multiplicity constraint violation occurred: An EntityReference can have no more than one related object, but the query returned more than one related object. при доступе к объектам CateringService через ссылку на объект. Мы используем ленивый подход, и ленивая загрузка включена.

При попытке получить доступ к «CateringService» с помощью Include("CateringService") все работает хорошо, но мы не можем просто заменить все вызовы SingleOrDefault и удалить все ленивые загрузки из проекта на этом этапе.

Пожалуйста, порекомендуйте.

ОБНОВЛЕНИЕ

Извините, что не совсем понятно. В базе данных есть единственная запись, соответствующая условию. Столбец Id установлен как первичный ключ, поэтому он уникален.

ОБНОВЛЕНИЕ 2

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

CreateTable(
            "dbo.CateringServices",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    Name = c.String(nullable: false, maxLength: 200),
                    CreatedDate = c.DateTime(nullable: false),
                    CultureString = c.String(maxLength: 10),
                    AddressId = c.Int(),
                    CateringServiceGroupId = c.Int(),
                    ContactInformationId = c.Int(),
                })
            .PrimaryKey(t => t.Id)
            .ForeignKey("dbo.Addresses", t => t.AddressId, cascadeDelete: true)
            .ForeignKey("dbo.CateringServiceGroups", t => t.CateringServiceGroupId)
            .ForeignKey("dbo.ContactInformation", t => t.ContactInformationId, cascadeDelete: true)
            .Index(t => t.AddressId)
            .Index(t => t.CateringServiceGroupId)
            .Index(t => t.ContactInformationId);

person danyloid    schedule 12.12.2013    source источник
comment
Каково определение query в вашем коде? (x.Id == query.CateringServiceId)   -  person Richard Deeming    schedule 16.12.2013
comment
Это экземпляр действительно простого класса, имеющего только одно свойство public Int32 CateringServiceId { get; set; }.   -  person danyloid    schedule 16.12.2013
comment
но я пытался использовать жестко запрограммированное значение, например. x => x.Id == 1. или любой другой существующий идентификатор в базе данных. все еще получаю тот же результат.   -  person danyloid    schedule 16.12.2013
comment
Вы проверили связанные таблицы (Addresses, CateringServiceGroups и ContactInformation), чтобы убедиться, что они содержат повторяющиеся записи?   -  person Richard Deeming    schedule 16.12.2013
comment
да, нет, но кажется, что проблема была в другом сопоставлении сущностей в следующих строках: this.HasOptional(x => x.CateringService).WithOptionalDependent().Map(x => x.MapKey("CateringServiceId"));. по какой-то причине при запросе таблицы CateringServices выполнялось левое внешнее соединение.   -  person danyloid    schedule 16.12.2013
comment
Не могли бы вы проверить SQL-запрос, сгенерированный Entity Framework, и, возможно, вы поймете, что не так? Основываясь на вашем описании, я думаю, что между CateringServices и другими объектами существует более одной связи, и это вызывает дублирование.   -  person Aleksei Poliakov    schedule 21.12.2013


Ответы (2)


Следует использовать FirstOrDefault вместо SingleOrDefault. Потому что у вашего короткого экрана одинаковое значение для Id cloumn. Так что вам нужно этого хотеть.

иначе вам нужно проверить, что идентификатор является первичным ключом. и установите флажок "Идентификация да" для столбца "Идентификатор"

потому что

FirstOrDefault()

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

Один или по умолчанию()

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

и обратитесь к этому LINQ: Когда использовать SingleOrDefault против FirstOrDefault () с критериями фильтрации

Обновлено:

Поскольку вы реконструировали базу данных, когда столбец Id еще не был установлен как IDENTITY, первая модель кода была сгенерирована с DatabaseGeneratedOption.None, установленным для свойства Id в сущности.

Это приводит к тому, что EF создает оператор вставки с установленным идентификатором, который больше не работает после изменения столбца на IDENTITY.

Вы должны вручную исправить эту конфигурацию, либо установив для нее значение DatabaseGeneratedOption.Identity, либо просто полностью удалив ее, так как это значение по умолчанию для целочисленных полей.

Вам нужно изменить

this.HasKey(e => e.Id);
   Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

Больше клиентов

EF Code First 5.0.rc Миграции не обновить свойство Identity

Entity Framework 5 сначала не создает базу данных

Изменить. Удалите старые значения таблицы и заново создайте их или удалите те же строки первичного ключа. Вам необходимо перегенерировать значения таблицы CateringServices :), если проблемы еще не устранены.

person Ramesh Rajendran    schedule 12.12.2013
comment
Верно. Но если вы читали заголовок вопроса, вы могли заметить, что это не совсем тот случай, когда следует использовать FirstOrDefault. Но проблема в том, что должна быть одна запись. Как есть в базе. И в любом случае ваш ответ не решает проблему с ошибкой «Произошло нарушение ограничения множественности отношений». - person danyloid; 12.12.2013
comment
Да, но ваш экран имеет такое же значение для Id cloumn. Так что вам нужно это сделать. - person Ramesh Rajendran; 12.12.2013
comment
Верно. Это то, о чем я спрашиваю. Я заявил, что идентификатор был уникальным в базе данных. - person danyloid; 12.12.2013
comment
Я проверил базу данных и параметр - идентификатор является первичным ключом, он уникален, и параметр действителен. - person danyloid; 12.12.2013
comment
прочитайте еще раз мой ответ. Вы установили IsIdentity = true в столбце идентификаторов? - person Ramesh Rajendran; 12.12.2013
comment
Можете ли вы показать настройки вашего первичного ключа? и есть ли настройки удостоверения? - person Ramesh Rajendran; 12.12.2013
comment
Я сделал. Я использую EF Code First и Fluent Mappings. Именно за это отвечает код - this.HasKey(x => x.Id); - person danyloid; 12.12.2013
comment
Я думаю, что идентификатор isidentity не установлен. Итак, у вас возникла проблема. Убедитесь, что установлен идентификатор isidentity :google.co.in/ - person Ramesh Rajendran; 12.12.2013
comment
Я также могу добавить беглое отображение, но это сделает вопрос слишком трудным для чтения. - person danyloid; 12.12.2013
comment
Я отредактировал свой ответ. Пожалуйста, проверьте его. - person Ramesh Rajendran; 12.12.2013
comment
Я обновил решение, пожалуйста, взгляните сейчас :) - person Ramesh Rajendran; 12.12.2013
comment
Мы не реконструировали базу данных. В проекте с самого начала использовался EF Code First. Мы начали испытывать проблему сразу после обновления до 6-й версии. Однако ваше решение сработало)) - person danyloid; 12.12.2013
comment
извините за снятие пометки с вопроса и спасибо за усилия. однако проект появился снова. похоже причина в другом. - person danyloid; 16.12.2013
comment
@danyloid - я думаю, что в вашей базе данных есть старые значения с тем же значением первичного ключа, поэтому вы получили ошибку, очистите таблицу и еще раз попробуйте - person Ramesh Rajendran; 17.12.2013

Вы можете использовать .Top(1) вместо .FirstOrDefault() или .SingleOrDefault().

Я новичок в Linq, но, как я знаю, top() вернет только указанное количество строк. Я не знаю о FirstOrDefault и SingleOrDefault.

person Anand    schedule 16.12.2013
comment
На самом деле вы должны использовать FirstOrDefault, иначе top(1) по-прежнему возвращает IEnumberable. FirstOrDefault() вернет первый элемент в последовательности, если есть какие-либо, или вернет null SingleOrDefault вернет null, если их нет, элемент, если есть один (и только один), и выдаст исключение если есть несколько предметов - person finman; 23.12.2013