Entity Framework - действительно ли необходимо чрезмерное использование EntityState.Unchanged? - PullRequest
0 голосов
/ 09 ноября 2019

Спасибо, что нашли время!

В настоящее время я создаю прототип интернет-магазина для смартфонов в рамках изучения Entity Framework. Я наткнулся на проблему, когда новые записи в моей базе данных добавляют дополнительные записи в связанные таблицы. Мне удалось обойти эту проблему, следуя этому посту Запретить добавление новой записи в связанный элемент таблицы в Entity Framework .

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

Пожалуйста, возьмите следующий код, который используется для проверки:

    public ActionResult CheckOut()
    {
        // Save cart
        Order order = new Order() { Payed = false, Canceled = false };
        db.Orders.Add(order);

        for (int i = 0; i < cartItems.Count; i++)
        {
            cartItems[i].Order = order;
            cartItems[i].OrderId = order.OrderId;

            db.CartItems.Add(cartItems[i]);

            db.Entry(cartItems[i].Item).State = EntityState.Unchanged;
            db.Entry(cartItems[i].Item.Memory).State = EntityState.Unchanged;
            db.Entry(cartItems[i].Item.ScreenSize).State = EntityState.Unchanged;
            db.Entry(cartItems[i].Item.OperatingSystem).State = EntityState.Unchanged;
        }

        db.SaveChanges();
        cartItems.Clear();

        return View();
    }

Метод берет все товары, которые пользователь положил в корзину, и добавляет их в базу данных. Если я не установлю State на EntityState.Unchanged, ссылочные сущности будут добавлены как новые записи в соответствующие таблицы.

Для лучшего понимания вот сущность Item и класс CartItem:

public class Item
{
    public int ItemId { get; set; }
    public int MemoryId { get; set; }
    public int OperatingSystemId { get; set; }
    public int BrandId { get; set; }
    public int ScreenSizeId { get; set; }
    public string Name { get; set; }
    public float Price { get; set; }

    public Memory Memory { get; set; }
    public OperatingSystem OperatingSystem { get; set; }
    public ScreenSize ScreenSize { get; set; }
}

public class CartItem
{
    public int CartItemId { get; set; }
    public int OrderId { get; set; }
    public int ItemId { get; set; }
    public int Quantity { get; set; }

    public Order Order { get; set; }
    public Item Item{ get; set; }
}

Что действительно меня раздражает, так это то, что если я объединю код, который используется для добавления товаров в корзину, и метод оформления заказа, я вообще не вижу этой проблемы (обратите внимание на отсутствие state = EntityState.Unchanged) .

    public ActionResult ProblemFreeCheckOut()
    {
        // Add Items to cart...
        var item1= db.Items.Include(i => i.Memory).Include(i => i.OperatingSystem).Include(i => i.ScreenSize).Where(i => i.ItemId == 1);
        var item2= db.Items.Include(i => i.Memory).Include(i => i.OperatingSystem).Include(i => i.ScreenSize).Where(i => i.ItemId== 2);

        CartItems List<CartItems> = new List<CartItem>();

        cartItems.Add(new CartItem { Quantity = 1, ItemId = item1.First().ItemId, Item = item1.First() });
        cartItems.Add(new CartItem { Quantity = 1, ItemId= item2.First().ItemId, Item = item2.First() });

        // Save cart
        Order order = new Order() { Payed = false, Canceled = false };
        db.Orders.Add(order);

        for (int i = 0; i < cartItems.Count; i++)
        {
            cartItems[i].Order = order;
            cartItems[i].OrderId = order.OrderId;
            db.CartItems.Add(cartItems[i]);
        }

        db.SaveChanges();
        cartItems.Clear();

        return View();
    }

Чтобы подвести итог и уточнить, что я пытаюсь сделать: я хочу иметь возможность разбить код выше на две части: одна Add метод и один Checkout метод. Метод Add добавляет элементы из базы данных в список элементов, которые впоследствии будут использоваться методом Checkout. У меня это работает, из-за чрезмерного использования EntityState.Unchanged - действительно ли это нужно?

Большое спасибо, если вы зашли так далеко, я приветствую вас!

1 Ответ

3 голосов
/ 09 ноября 2019

Посмотрите документацию для метода Add (TEntity):

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

Так что, вызывая метод Add, вы говорите EF: «обрабатывать все, что я только что подключил кконтекст (через граф отношений) как новый элемент ".
Во втором примере вы не столкнетесь с проблемой, потому что связанные сущности уже отслеживаются при Include их. В этом случае EF просто сохраняет значение Unchanged, в результате чего они игнорируются в течение SaveChanges().

Чисто с технической точки зрения, у вас есть два варианта. Либо:
1) делайте то, что вы делаете во втором примере - отслеживайте связанные сущности перед вызовом метода Add(), чтобы EF знал, что нужно обрабатывать их как Unchanged.
или
2) вместосразу добавив граф сущностей

db.CartItems.Add(cartItem);

, просто присоедините его (по умолчанию все сущности будут отслеживаться как Unchanged), а затем отметьте cartItem как добавленное:

db.CartItems.Attach(cartItem).State = EntityState.Added;

В этом последнем пункте - может даже оказаться, что достаточно db.CartItems.Attach(cartItem);, поскольку EF устанавливает состояние в Added для сущностей, для которых не установлены поля первичного ключа. Моя память немного размыта в этом вопросе. В любом случае это хорошее место для установки точки останова и отладки, чтобы увидеть, как EF отслеживает магию. На эту тему есть отличный пост в блоге, который я рекомендую:
https://docs.microsoft.com/en-us/archive/msdn-magazine/2013/april/data-points-why-does-entity-framework-reinsert-existing-objects-into-my-database

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