Entity Framework «Многие ко многим» не спасет

#c# #asp.net-mvc #entity-framework #many-to-many

#c# #asp.net-mvc #entity-framework #»многие ко многим»

Вопрос:

У меня есть простой «Многие ко многим». Категории в продуктах. У каждого есть виртуальный список другого. Я создаю продукт, подобный этому:

 product = new Product()
{
    AccountId = this.AccountId,
    Name = this.ProductName,
    Price = this.ProductPrice,
    Slug = this.ProductSlug,
    Sku = this.ProductSku,
    Favorite = true,
    Categories = new List<Category>()
                {
                    category 
                }
};

product.Id = productManager.Save(product);
  

Затем, когда я перейду к его сохранению, это не сохранит «многие ко многим». Я погуглил и попробовал довольно много разных вариантов этого кода, и все еще ничего:

 public new String Save(Product data)
{
    try
    {
        var entity = GetById(data.Id);

        if (entity == null)
        {
            this.Context.Set<Product>().Add(data);
        }
        else
        {
            this.Context.Entry(entity).CurrentValues.SetValues(data);
        }

        data.Id = this.Context.SaveChanges();

        var product = Context.Products
            .Include("Categories")
            .FirstOrDefault(t => t.Id == data.Id);

        /**
            * Categories
            */
        var categories = this.Context.Categories
            .Where(t => t.AccountId == data.AccountId);

        var productCategories = new List<Category>();

        if (data.SelectedCategoryIds != null amp;amp; data.SelectedCategoryIds.Any())
        {
            productCategories.AddRange(categories
                .Where(category => data.SelectedCategoryIds.Contains(category.Id)));
        }

        product.Categories.Clear();
        product.Categories.AddRange(productCategories);

        this.Context.SaveChanges();

        return data.Id;
    }
    catch (Exception ex)
    {
        Log.Error(ex);

        return null;
    }
}
  

Чего мне здесь не хватает? Почему это не сохранит мои категории «многие ко многим»?

Комментарии:

1. Есть ли у вас какие-либо другие подробности, кроме того, что это не сохранится? Выдает ли это исключение? Что-нибудь попадает в базу данных? Также кажется странным, что вы устанавливаете идентификатор продукта в качестве результата context.SaveChanges(). Этот метод возвращает количество объектов, записанных в базу данных, а не идентификатор.

2. Почему? Позвольте мне подробнее остановиться на этом. Почему??? Серьезно, однако, зачем вы создали Save метод, который все это делает? Вы в основном воссоздаете SaveChanges в Entity Framework и выполняете работу не так хорошо.

3. @Smith.h.Neil — Исключений нет. Продукт отлично сохраняет. Категории — это единственное, что не сохраняется.

4. Как говорит @ChrisPratt, вы пробовали просто прикрепить продукт, а затем вызвать context.SaveChanges() вместо использования вашего метода сохранения?

5. @Chris — Я не могу просто вызвать SaveChanges. Данные не прикрепляются, когда я передаю их обратно из представления, потому что я не поддерживаю контекст открытым. Кроме того, вся первая часть на самом деле находится в общем методе сохранения, который я здесь не показывал, но это тот же код.

Ответ №1:

Технически это не ответ, но он слишком длинный для комментария, и это нужно сказать. Похоже, вы пытаетесь абстрагироваться от некоторых элементов Entity Framework, но это абсолютно неправильный способ сделать это. Например, в одном из моих проектов у меня есть сервис, который абстрагирует Entity Framework от остальной части моего приложения, и вот некоторый соответствующий код из этого, чтобы продемонстрировать разницу:

 public virtual void Update<TEntity>(TEntity entity)
    where TEntity : class
{
    context.Set<TEntity>().Attach(entity);
    context.Entry(entity).State = EntityState.Modified;
}

public virtual void Save()
{
    try
    {
        context.SaveChanges();
    }
    catch (DbEntityValidationException ex)
    {
        var errorMessages = ex.EntityValidationErrors
            .SelectMany(x => x.ValidationErrors)
            .Select(x => x.ErrorMessage);
        var fullErrorMessage = string.Join("; ", errorMessages);
        var exceptionMessage = string.Concat(ex.Message, " The validation errors are: ", fullErrorMessage);
        throw new DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors);
    }
}
  

В моем приложении, таким образом, это все, что происходит:

 var entity = new Something { ... };
service.Update<Something>(entity);
service.Save();
  

Итак, в приведенном выше коде происходит довольно много изменений, поэтому позвольте мне отступить на минуту. Во-первых, мой сервис использует универсальные методы, поэтому я могу работать с любой сущностью без необходимости писать новые методы или классы сервисов. <TEntity> Материал — это то, что заставляет это работать, и он не является строго обязательным. Кроме того, когда я позже это сделаю Update<Something> , я использую этот универсальный метод, поэтому указываю класс, с которым я работаю, в данном случае Something . Единственная часть, на которую вам нужно обратить внимание, — это эти две строки моего Update<> метода, которые я собираюсь изменить в соответствии с вашей ситуацией:

 context.Set<Product>().Attach(product);
context.Entry(product).State = EntityState.Modified;
  

Тогда единственное, что необходимо для сохранения изменений (из моего Save метода):

 context.SaveChanges();
  

Вот и все. Если одного этого кода недостаточно для обновления вашей сущности, то, честно говоря, вы делаете что-то не так, и вам нужно развернуть свой код и выяснить, что это такое.