Я новичок в Entity Framework Core и учусь.
У меня вопрос: у меня есть три таблицы с отношениями "многие ко многим" (Product, ProductCategory, Categories). Все работает нормально, я могу обновлять, удалять и добавлять базу данных.
Но я не мог добавить Product
данные в связанные таблицы. Он просто вставляется в таблицу Product
, но я хочу добавить данные Id в ProductCategories
.
Спасибо, что помогли мне здесь.
Это мой код:
Общий репозиторий
public class EfCoreGenericRepository<TEntity, TContext> : IRepository<TEntity>
where TEntity : class
where TContext : DbContext, new()
{
public virtual void Create(TEntity entity)
{
using (var context = new TContext())
{
context.Set<TEntity>().Add(entity);
context.SaveChanges();
}
}
public void Delete(TEntity entity)
{
using (var context = new TContext())
{
context.Set<TEntity>().Remove(entity);
context.SaveChanges();
}
}
public List<TEntity> GetAll()
{
using (var context = new TContext())
{
return context.Set<TEntity>().ToList();
}
}
public TEntity GetById(int id)
{
using (var context = new TContext())
{
return context.Set<TEntity>().Find(id);
}
}
public virtual void Update(TEntity entity)
{
using (var context = new TContext())
{
context.Entry(entity).State = EntityState.Modified;
context.SaveChanges();
}
}
}
ПродуктРепозиторий
public class EfCoreProductRepository : EfCoreGenericRepository<Product, FoodContext>, IProductRepository
{
public Product GetByIdWithCategories(int id)
{
using (var context = new FoodContext())
{
return context.Products
.Where(p => p.ProductId == id)
.Include(p => p.ProductCategories)
.ThenInclude(pc => pc.Category)
.FirstOrDefault();
}
}
public List<Product> GetProductsByCategory(string name)
{
using (var context = new FoodContext())
{
var products = context.Products.AsQueryable();
if (!string.IsNullOrEmpty(name))
{
products = products.Include(i => i.ProductCategories)
.ThenInclude(i => i.Category)
.Where(i => i.ProductCategories.Any(a => a.Category.Name.ToLower() == name.ToLower()));
}
return products.ToList();
}
}
public void Update(Product entity, int[] categoryIds)
{
using (var context = new FoodContext())
{
var product = context.Products
.Include(i => i.ProductCategories)
.FirstOrDefault(i => i.ProductId == entity.ProductId);
if (product != null)
{
product.Name = entity.Name;
product.Price = entity.Price;
product.ImageUrl = entity.ImageUrl;
product.ProductCategories = categoryIds.Select(catid => new ProductCategory() {
ProductId = entity.ProductId,
CategoryId = catid
}).ToList();
}
context.SaveChanges();
}
}
// I may override Create code here.
}
Почтовый метод MVC
[HttpPost]
public async Task<IActionResult> CreateProduct(ProductModel model, IFormFile file)
{
if (ModelState.IsValid)
{
if (file != null)
{
var extension = Path.GetExtension(file.FileName);
var randomName = string.Format($"{DateTime.Now.Ticks}{extension}");
model.ImageUrl = randomName;
var path = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot\\img\\Products", randomName);
using (var stream = new FileStream(path, FileMode.Create))
{
await file.CopyToAsync(stream);
}
}
var entity = new Product()
{
Name = model.Name,
Price = model.Price,
ImageUrl = model.ImageUrl,
CategoryId = model.CategoryId
};
if (_productService.Create(entity))
{
TempData.Put("message", new AlertMessage
{
Title = $"{entity.Name} named product added successfully",
Message = $"{entity.Name} named product added successfully",
AlertType = "alert-success"
});
return RedirectToAction("ProductList");
};
TempData.Put("message", new AlertMessage
{
Title = _productService.ErrorMessage,
Message = _productService.ErrorMessage,
});
}
ViewBag.Categories = _categoryService.GetAll();
return View(model);
}
Вы можете запросить дополнительный код, если вам нужно его увидеть. Спасибо!
Правка ---> Классы сущностей
Категория.cs
public class Category
{
public int CategoryId { get; set; }
public string Name { get; set; }
public string ImageUrl { get; set; }
public List<ProductCategory> ProductCategories{get; set;}
}
Продукт.cs
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public double? Price { get; set; }
public bool IsApproved { get; set; }
public int? CategoryId { get; set; }
public string ImageUrl { get; set; }
public List<ProductCategory> ProductCategories{get; set;}
}
ProductCategories.cs
public class ProductCategory
{
public int CategoryId { get; set; }
public Category Category { get; set; }
public int ProductId { get; set; }
public Product Product{get; set;}
}
Спасибо за ответ. Я также добавил классы сущностей. CategoryId имеет значение null, потому что я хотел вручную управлять им с помощью сообщений об ошибках.
Спасибо за обновление. Почему у вас есть публичный int? CategoryId в классе продукта? ProductCategory должен управлять вашими отношениями между Product и Category.
Вы сказали много ко многим. Это правда? Может ли Продукт действительно быть в нескольких категориях? Я могу понять категорию, имеющую много продуктов, но не обязательно наоборот.
если продукт имеет несколько категорий, то какова цель int? CategoryId
в Product
классе?
@memo1093 memo1093 Я не вижу кода, в котором он пытается вставить запись в ProductCategory
. Назначение Product.CategoryId = model.CategoryId
волшебным образом не добавит запись в ProductCategory
. После добавления продукта _productService.Create(entity)
вы сможете получить идентификатор вновь вставленной записи из переменной entity
, а затем выполнить другую операцию базы данных для записи ProductCategory
. В качестве примечания: нет необходимости в CategoryId
в продукте, поскольку существует отношение многие ко многим.
Я могу получить идентификатор категории объекта, но я не могу вставить его в ProductCategory, как я могу это сделать, я не знаю.
Я сделал это благодаря тебе! Я вставил данные с помощью base.Create(entity); а затем я написал еще одну, используя последовательность. Не знаю насколько правда, но поделюсь кодом.
Спасибо Пирату. Я решил проблему. Я новичок в efcore, но я знал, что многие отношения не нужны. Я сделал это для многих продуктов со многими категориями, но позже передумал. Может быть, я смогу использовать его для следующих кодов.
public override void Create(Product entity)
{
base.Create(entity);
using (var context = new FoodContext())
{
var product = context.Products
.Where(i=>i.ProductId==entity.ProductId)
.Include(i=>i.ProductCategories).FirstOrDefault();
product.ProductCategories.Add(new ProductCategory(){
ProductId=entity.ProductId,
CategoryId=(int)entity.CategoryId
});
context.SaveChanges();
}
}
Примечание. Я не знаю, насколько верно использование двойного использования кодового блока.
Можете ли вы добавить свои классы Entity к вопросу? Вы уверены, что model.CategoryId не равен нулю?