EntityFrameworkCore вставляет существующие связанные элементы - PullRequest
0 голосов
/ 18 ноября 2018

Рассмотрим

 public class Item
 {
    public int Id{get;set;}
    public string Name{get;set;}
    public List<ItemTag> ItemTags{get;set;}
 }

 public class ItemTag
 {
    public int Id{get;set;}
    public int Name{get;set;}
 }

Теперь я использую ядро ​​Entity Framework для добавления ItemTag к Item.Это работает просто отлично.

Теперь я добавляю вторую метку к тому же предмету.При сохранении передается весь объект, включая существующие связанные ItemTags.Затем EF пытается вставить существующий тег ItemTag, который завершается ошибкой, за исключением «Невозможно вставить значение в столбец идентификации ...»

Так как же предотвратить вставку существующего объекта?

Мой обходной путь - циклически перебирать ItemTags и устанавливать любой, у которого есть Id, в EntityState. Без изменений, чтобы заставить его не сохранять его.Но, похоже, такой обходной путь не требуется.

Это код, который сохраняет элемент:

//Get the current item, so that only updated fields are saved to the database.
var item = await this.DbContext.Items.SingleAsync(a => a.Id == itemInput.Id);
item.UpdatedBy = this._applicationUserProvider.CurrentAppUserId;
item.Updated = DateTimeOffset.UtcNow;

//Use Automapper to map fields.
this._mapper.Map(itemInput, item);

//Workaround for issue.
foreach (var itemTag in item.ItemTags)
{
    var entry = this.DbContext.Entry(itemTag);
    if (itemTag.Id > 0)
    {
        entry.State = EntityState.Unchanged;
    }
}

await this.SaveChangesAsync();

Ответы [ 2 ]

0 голосов
/ 19 ноября 2018

Для вставки новой ItemTag, вы можете вставить в таблицу ItemTag напрямую, не отражая Item.

Определите вашу модель, как показано ниже:

public class ItemTag
{
    public int Id { get; set; }
    public int Name { get; set; }
    public int ItemId { get; set; }
    public virtual Item Item { get; set; }
}

Попробуйте установить ItemId для ItemTag, чтобы вставить новый ItemTag для Item.

Если вы предпочитаете вставить Item с ItemTag, вы можете попробовать JsonPatchDocument, который описывает, как работать с моделью.

Попробуйте сослаться Патч JSON с ASP.net Core .

Для JsonPatchDocument необходимо сгенерировать JsonPatchDocument<Item> на стороне клиента.попробуйте сослаться ASP Core PatchDocument, возвращающий неверный ввод .

0 голосов
/ 18 ноября 2018

AutoMapper не подходит для возврата к постоянным или доменным моделям.Автор AutoMapper заявил .

Это также не очень хорошо работает, если EF (Core) отслеживает изменения .

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

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

У вас также есть возможность Attach и Detach сущностей.

Из ссылки в блоге:

Роуэн Миллер суммировала новое поведение вПроблема GitHub (bit.ly/295goxw):

Add: добавляет каждую достижимую сущность, которая еще не отслеживается.

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

Обновление: то же, что и «Присоединить», но объекты помечены как измененные.

Удалить: То же, что и «Присоединить», а затем пометить корень как удаленный.Поскольку каскадное удаление теперь происходит в SaveChanges, это позволяет каскадным правилам передаваться сущностям позже.

Таким образом, вам придется прикреплять свои элементы (если вы хотите добавлять новые только без первичнойkey) или позвоните Update/UpdateRange на DbSet, чтобы обновить те с ключом и добавить те без.

Либо обработайте его самостоятельно, установив / изменив его отслеживаемое состояние, как вы уже сделали.Но имейте в виду, Unchanged не будет обновлять переданные объекты.

...