#c# #asp.net-core #entity-framework-core #.net-6.0
#c# #asp.сетевое ядро #сущность-структура-ядро #.net-6.0
Вопрос:
Я не нашел никаких ресурсов по этому вопросу, вероятно, из-за неправильной формулировки.
Настройка — это объект Lake
, который содержит список Fish
. Каждая Fish
Сущность также содержит Сущность своего Рода FishKind
. Через какой-то API я получаю Lake
объект, уже содержащий много рыбы. По какой-то причине существуют рыбы одного и того же вида — gt; поэтому у нас есть несколько объектов/экземпляров класса FishKind, которые имеют один и тот же идентификатор.
Вот некоторый фиктивный код об объекте Hirachy:
class Lake { public int LakeId; public Listlt;Fishgt; Fish; } class Fish { public int FishId; public FishKind Kind; } class FishKind { public int FishKindId; FishKind(int id) { FishKindId = id; } } // this is how example data from the API could look like - I don't create objects like this in my code. I get them via the API // The FishKind have the same id/data however a different instances in C# // The FishKind have valid IDs which are also already in the DB // only Lake and Fish should be created var lake = new Lake(); var idOfShark = 29; lake.Fish.Add(new Fish("Tony", new FishKind(idOfShark))); lake.Fish.Add(new Fish("Helen", new FishKind(idOfShark)));
Для дальнейшего разъяснения — пример данных, полученных через API
{ "LakeId":0, "Fish":[ { "FishId":0, "Name":"Tony", "Kind":{ "FishKindId":29 } }, { "FishId":0, "Name":"Helen", "Kind":{ "FishKindId":29 } } ] }
- Когда я это делаю
db.AddAsync(Lake)
, это не удается, потому что у меня уже есть такая рыба, добавленная в базу данных - Когда я пытаюсь
db.Update(Lake)
, это работает до тех пор, пока у меня нет 2 рыбок одного и того же вида. Если они одного и того же рода, я получаю:The instance of entity type 'FishKind' cannot be tracked because another instance with the key value '{FishKindId: 1}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.'
Один обходной путь, который пришел мне в голову, — это замена всех экземпляров FishKind уже отслеживаемым объектом, однако это кажется сложным и похожим на хакерское решение.
Комментарии:
1. @T. Трасудейн Я написал только минимальный код. Убедитесь, что у всех объектов есть идентификаторы, иначе я не смогу создать миграцию. Я отредактировал сообщение, чтобы добавить идентификаторы
2. @T. Трасудейн Я не хочу создавать новый вид рыб. Виды, которые, вероятно, уже существуют, образуют создание другого озера. (или причина в графическом интерфейсе при создании новой рыбы/озера я загружаю все виды из БД)
3. @T. Трасуден Я не хочу создавать новые виды. Но я получаю объекты через Rest, поэтому они отличаются. Вышеописанный обходной путь состоял бы в поиске всех рыбьих шкурок и замене их отслеживаемым объектом
4. Как насчет фактического кода, получающего данные из API, есть идеи, почему он создает новый экземпляр FishKind для каждой рыбы?
5. @T. Трасудейн, я думаю, это потому, что asp.net не знает, что объекты являются одними и теми же сущностями, и поэтому создает одинаковые объекты, но разные экземпляры
Ответ №1:
Посмотрите, где вы это делаете:
lake.Fish.Add(new Fish("Tony", new FishKind(idOfShark))); ^^^^^^^^^^^^^^^^^^^^^^^
Не делайте этого; вы постоянно создаете новые объекты с тем же идентификатором, что и существующий объект, о котором контекст уже знает. Либо повторное использование, о котором знает сущность:
var shark = context.FishKinds.Single(fk =gt; fk.FishKindId == 29); //if its local it will be returned, if it's not it will be fetched and remembered lake.Fish.Add(new Fish("Tony", shark)); lake.Fish.Add(new Fish("Mary", shark));
Или обновите объект Fish, чтобы у него был идентификатор FishKindId (или независимо от того, является ли имя столбца в базе данных, сопоставляемое с FiskKind PK), свойством int и установите для него значение 29 (idOfShark), оставьте объект FishKind нулевым.
Комментарии:
1. Это правильно, но я никогда
new FishKind(idOfShark)
не делаю этого с помощью JsonSerializer2. О, я понимаю.. Обращение к сущностям БД потенциально может привести к этому. Я могу придумать множество способов решения, самым простым из которых может быть «поместить FishKindId в рыбу, перечислить рыбу, передающую из fish.FishKind. FishKindId в fisjh.FishKindId и установите значение FISH.FiskKind равным нулю
3. (По сути, восстановление графа объектов, чтобы быть чем-то, что может выдержать отслеживание изменений). Вы также можете перечислить рыбу, заменив все
theFish.FishKind = context.FishKinds.Single(fk =gt; fk.FishKindId == theFish.FishKind.FishKindId)
4. Благодаря вашему ответу я наткнулся на
ForeignKey("FishKindId")]
то, что в настоящее время тестирую. Я могу изменить API таким образом, чтобы он давал мне только FishKindId, а не полный объект5. Исправления опечаток в первоначальном комментарии: О, я понимаю.. Обращение к сущностям БД потенциально может привести к этому. Я могу придумать множество способов решения , самым простым из которых может быть «ввести
FishKindId
Fish
, перечислитьlake.Fish
идентификатор переноса изlake.Fish.FishKind.FishKindId
вlake.Fish.FishKindId
и установитьlake.Fish.FishKind
значение null