Как правильно сохранить сложный объект с помощью EF CoreC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Как правильно сохранить сложный объект с помощью EF Core

Сообщение Anonymous »

У меня проблема с сохранением сложного объекта...
(Упрощенные) объекты выглядят так:

Код: Выделить всё

public class Excavator
{
public int Id { get; set; }

public ExcavatorType Type { get; set; } = new();

public IList Properties { get; set; } = new List();

public IList SpareParts { get; set; } = new List();
}

public class ExcavatorType
{
public int Id { get; set; }

public IList PropertyTypes { get; set; } = new List();

public IList ExcavatorsOfThisType { get; set; } = new List();
}

public class ExcavatorProperty
{
public int Id { get; set; }

public ExcavatorPropertyType PropertyType { get; set; } = null!;
}

public class SparePart
{
public int Id { get; set; }

public IList Excavators { get; set; } = new List();
}

public class ExcavatorPropertyType
{
public int Id { get; set; }

public IList ExcavatorTypesWithThisProperty { get; set; } = new List()!;
}
Я хочу сохранить экскаватор (который имеет тип Excavator). Экземпляры ExcavatorType и SparePart уже существуют в базе данных (как и ExcavatorPropertyType).
Я заполнил экскаватор данными из формы и прочитав ответ на этот вопрос, я попробовал следующее:

Код: Выделить всё

var excavatorTypeTmp = await context.ExcavatorTypes
.FirstAsync(et => et.Id == excavator.Type.Id);
excavator.Type = excavatorTypeTmp;

var sparePartsIds = excavator.SpareParts.Select(sp => sp.Id);
excavator.SpareParts = await context.SpareParts
.Where(sp => sparePartsIds.Contains(sp.Id))
.ToListAsync();

context.Add(excavator);
await context.SaveChangesAsync();
Я получил ошибку: «Экземпляр типа сущности «ExcavatorType» не может быть отслежен, поскольку другой экземпляр с тем же значением ключа для {'Id'} уже отслеживается. Когда прикрепляя существующие объекты, убедитесь, что прикреплен только один экземпляр объекта с заданным значением ключа."
Я также пробовал .Attach() и .AttachRange() :

Код: Выделить всё

context.Attach(excavator.Type);
context.AttachRange(excavator.SpareParts);

context.Add(excavator);
await context.SaveChangesAsync();
Я получил ошибку: «Экземпляр типа сущности «Экскаватор» не может быть отслежен, поскольку другой экземпляр с тем же значением ключа для {'Id'} уже отслеживается. Когда прикрепляя существующие объекты, убедитесь, что прикреплен только один экземпляр объекта с заданным значением ключа."
Затем я даже попробовал (из-за некоторых комментариев в ранее упомянутом вопросе):

Код: Выделить всё

var typeTmp = excavator.Type;
excavator.Type = null!;
context.Attach(typeTmp);
excavator.Type = typeTmp;

var sparePartsTmp = excavator.SpareParts;
excavator.SpareParts = null!;
context.AttachRange(sparePartsTmp);
excavator.SpareParts = sparePartsTmp;

context.Add(excavator);
await context.SaveChangesAsync();
У меня возникла ошибка: Такая же, как и предыдущая.
Если я не ошибаюсь, проблема возникает при попытке прикрепить запчасти (

Код: Выделить всё

context.AttachRange(sparePartsTmp);
).
Еще одна вещь, которую я обнаружил, это то, что когда я не коплю запасные части, проблем нет. Экскаватор, кажется, сохраняется правильно (но, конечно, без запасных частей).
Поэтому я подумал, что, возможно, проблема в том, что я ссылаюсь на одни и те же объекты экскаватора (я пытаюсь присоединить несколько экскаваторов с помощью один и тот же идентификатор) как из excavator.Type, так и из excavator.SpareParts.
И когда я пытался сохранить его таким образом (я избавился от ссылок на excavator из запасных части, присвоив значение null)...:

Код: Выделить всё

context.Attach(excavator.Type);

var excavatorsTmp = new List(excavator.SpareParts.Count);
for (int i = 0; i < excavator.SpareParts.Count; i++)
{
var sparePart = excavator.SpareParts[i];
excavatorsTmp.Add(sparePart.Excavators);
sparePart.Excavators = null!;
}
context.AttachRange(excavator.SpareParts);

context.Add(excavator);
await context.SaveChangesAsync();
...вроде все работает нормально — экскаватор был сохранен правильно.
Но я считаю, что есть другой (более разумный) способ сохранить экскаватор .
Изменить (подробнее):
Я использую оператор using (using декларацию, если быть точным). Я создаю контекст следующим образом:

Код: Выделить всё

using var context = factory.CreateDbContext();
Где .CreateDbContext() выглядит так:

Код: Выделить всё

var connectionString = GetConnectionString();
var optionsBuilder = new DbContextOptionsBuilder();
optionsBuilder.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));
return new MyDbContext(optionsBuilder.Options);
Я сделал это таким образом, потому что это приложение Blazor (серверное), и я видел, как это делается здесь.

Подробнее здесь: https://stackoverflow.com/questions/734 ... ng-ef-core
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Как отправить сложный объект с изображениями на сервер .net Core 8 с помощью JavaScript?
    Anonymous » » в форуме C#
    0 Ответы
    25 Просмотры
    Последнее сообщение Anonymous
  • Как передать сложный объект C# с помощью FromQuery
    Anonymous » » в форуме C#
    0 Ответы
    19 Просмотры
    Последнее сообщение Anonymous
  • Как отправить сложный объект в атрибуте DynamoDB с помощью SDK?
    Anonymous » » в форуме JAVA
    0 Ответы
    2 Просмотры
    Последнее сообщение Anonymous
  • Как отправить сложный объект в атрибуте DynamoDB с помощью SDK?
    Anonymous » » в форуме JAVA
    0 Ответы
    2 Просмотры
    Последнее сообщение Anonymous
  • Сложный выбор из БД с помощью EF Core без реализации запроса
    Anonymous » » в форуме C#
    0 Ответы
    14 Просмотры
    Последнее сообщение Anonymous

Вернуться в «C#»