EF Core неправильно обновляет элементы внешнего ключа

Я пытаюсь обновить user и соответствующие им items, но получаю странное поведение. Точнее, user обновляется, но items добавляются в таблицу items, а предыдущие items, которые уже присутствовали в таблице, имеют UserId из null, а новые items имеют обновленные UserId.

Я пробовал разные вещи, такие как включение UserId и ItemId в мой вызов REST, но это приводит к System.InvalidOperationException для items. Однако добавление user и соответствующих им items в таблицы работает нормально.

public HttpStatusCode UpdateUsersAndItems(User user)
{
    if (ModelState.IsValid)
    {
        using (MyContext myContext = _myContext as MyContext)
        {
            User updateUser = myContext?.Users?.Include(i => i.Items).FirstOrDefault(u => u != null && u.UserName == user.UserName);

            if(updateUser != null)
            {
                updateUser.UserName = user.UserName;
                updateUser.Dob = user.Dob;
                updateUser.Location = user.Location;
                updateUser.Items = user.Items;

                myContext?.Users?.Update(updateUser);

                int changes = myContext.SaveChanges();

                if (changes > 0)
                {
                    return HttpStatusCode.Created;
                }
            }
        }
    }

    return HttpStatusCode.NotModified;
}

namespace TestWebApplication.Database
{
    public class User
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int UserId { get; set; }
        public string UserName { get; set; }
        public string Dob { get; set; }
        public string Location { get; set; }

        public ICollection<Items> Items { get; set; }
    }
}


namespace TestWebApplication.Database
{
    public class Items
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int ItemId { get; set; }
        public string Item { get; set; }
        public string Category { get; set; }
        public string Type { get; set; }

        public int? UserId { get; set; }

        [ForeignKey("UserId")]
        public virtual User User { get; set; }
    }
}

Звонок на отдых

{
    "username": "xxx",
    "dob": "xxx",
    "location": "xxx",
    "items":[{
        "item": "xxx",
        "category": "xxx",
        "type": "xxx"
        },
        {
        "item": "xxx",
        "category": "xxx",
        "type": "xxx"
        },
        {
        "item": "xxx",
        "category": "xxx",
        "type": "xxx"
        }]
}

person user1574598    schedule 11.04.2020    source источник
comment
То есть вы говорите, что при сохранении EF удаляет идентификаторы всех существующих пользователей в таблице и сохраняет только тех, кого вы только что подключили?   -  person Caius Jard    schedule 11.04.2020
comment
Вы заменяете всю коллекцию Items здесь: updateUser.Items = user.Items;   -  person Frank Nielsen    schedule 11.04.2020


Ответы (1)


Вы должны пройти через каждый элемент и изменить его свойства.

Что-то вроде этого.

       using (MyContext myContext = _myContext as MyContext)
        {
            User updateUser = myContext?.Users?.Include(i => i.Items).FirstOrDefault(u => u != null && u.Id == user.Id);

            if(updateUser != null)
            {
                updateUser.UserName = user.UserName;
                updateUser.Dob = user.Dob;
                updateUser.Location = user.Location;
                foreach( var userItem in user.Items )
                {
                   var updateItem = updateUser.Items.SingleOrDefault( i => i.Id == userItem.Id );
                   if( updateItem == null )
                   {
                     updateItem = new Items {
                       Type = userItem.Type,
                       Category = userItem.Category
                     };
                     updateUser.Items.Add(updateItem);
                   }
                   else
                   {
                     updateItem.Type = userItem.Type;
                     updateItem.Category = userItem.Category;
                   }
                }


                int changes = myContext.SaveChanges();

                if (changes > 0)
                {
                    return HttpStatusCode.Created;
                }
            }
        }

я не вижу, как вы уникально идентифицируете свои элементы, но не предоставляете свои первичные ключи внешнему интерфейсу (веб)

person Frank Nielsen    schedule 11.04.2020
comment
правильным было бы updateUser.Items.SingleOrDefault(i => i.Id == userItem.Id), но я не знаю, есть ли у вас Id на типе User? - person Frank Nielsen; 11.04.2020
comment
Потрясающий! Это работает, спасибо. Пожалуйста, проигнорируйте мой последний комментарий (который я удалил), так как я сначала не понял код! Я изменил его обратно на SingleOrDefault, и он все еще работает. У меня есть id в моем классе user, если только я не читаю ваш комментарий неправильно. Еще одна вещь, которую вы мне прояснили, это использование ids в остальных вызовах и в Интернете - отлично! - person user1574598; 12.04.2020