EF Core : Cómo insertar los datos tablas releadas

Soy nuevo en Entity Framework Core y aprendizaje.

Tengo una pregunta: Tengo tres tablas con muchas relaciones (Producto, ProductCategory, Categorías). Todo funciona bien, puedo actualizar, borrar y añadir la base de datos.

Pero no pude añadir Product datos a cuadros conexos. Sólo inserta en el Product tabla, pero quiero añadir datos de identificación a ProductCategories.

Gracias por ayudarme.

Este es mi código:

Repositorio genérico

public class EfCoreGenericRepository : IRepository
        where TEntity : class
        where TContext : DbContext, new()
{
    public virtual void Create(TEntity entity)
    {
        using (var context = new TContext())
        {
            context.Set().Add(entity);
            context.SaveChanges();
        }
    }

    public void Delete(TEntity entity)
    {
        using (var context = new TContext())
        {
            context.Set().Remove(entity);
            context.SaveChanges();
        }
    }

    public List GetAll()
    {
        using (var context = new TContext())
        {
            return context.Set().ToList();
        }
    }

    public TEntity GetById(int id)
    {
        using (var context = new TContext())
        {
            return context.Set().Find(id);
        }
    }

    public virtual void Update(TEntity entity)
    {
        using (var context = new TContext())
        {
            context.Entry(entity).State = EntityState.Modified;
            context.SaveChanges();
        }
    }
}

ProductRepository

public class EfCoreProductRepository : EfCoreGenericRepository, 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 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 Método de publicación

[HttpPost]
public async Task 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);
}

Puedes pedir más código si necesitas verlo. ¡Gracias por ahora!

Editar --- Clases de Entidad

Categoría.cs

public class Category
    {
        public int CategoryId { get; set; }
        public string Name { get; set; }

        public string ImageUrl { get; set; }

        public List ProductCategories{get; set;}
    }

Producto.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 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;}
    }

Pregunta hecha hace 3 años, 4 meses, 28 días - Por quantumcoderd26d


3 Respuestas:

  • Gracias a Pirate. He resuelto el problema. Soy nuevo en efcore pero era consciente de muchas a muchas relaciones innecesarias. Había hecho por muchos productos con muchas categorías pero cambié de opinión más tarde. Tal vez pueda usarlo para los próximos códigos.

    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();
            }
        }
    

    Nota: No sé lo cierto usando doble código-block

    Respondida el Dec 18, 2020 a las 14:37 - por rubyrover

    Votos positivos: 0 | Votos negativos: 0

  • En la clase EfCoreProductRepository, en el método Update(Product entity, int[] categoryIds), estás tratando de insertar nuevas relaciones ProductCategory directamente asignándolas al producto existente. Sin embargo, esto puede causar problemas, ya que estás creando nuevas instancias de ProductCategory en lugar de simplemente asociar las categorías existentes al producto.

    Para agregar correctamente relaciones ProductCategory a un producto existente, necesitas hacer lo siguiente:

    Primero, obtén el producto existente de la base de datos y luego actualiza las categorías asociadas. En lugar de crear nuevas instancias de ProductCategory, simplemente asigna las categorías existentes al producto. Aquí te dejo una forma de hacerlo:

    csharp
    public void Update(Product entity, int[] categoryIds)
    {
        using (var context = new FoodContext())
        {
            var product = context.Products.Include(p => p.ProductCategories).FirstOrDefault(p => p.ProductId == entity.ProductId);
    
            if (product != null)
            {
                product.Name = entity.Name;
                product.Price = entity.Price;
                product.ImageUrl = entity.ImageUrl;
    
                // Elimina las relaciones existentes
                context.ProductCategories.RemoveRange(product.ProductCategories);
    
                // Asocia las nuevas categorías al producto
                foreach (var categoryId in categoryIds)
                {
                    product.ProductCategories.Add(new ProductCategory
                    {
                        ProductId = entity.ProductId,
                        CategoryId = categoryId
                    });
                }
    
                context.SaveChanges();
            }
        }
    }
    

    Con este código, primero se eliminan las relaciones existentes del producto con las categorías, y luego se agregan las nuevas relaciones utilizando los categoryIds proporcionados. Luego, al guardar los cambios en el contexto, se actualizarán las relaciones en la base de datos.

    Espero que esta solución te ayude a agregar correctamente las relaciones ProductCategory al producto existente. Si tienes más preguntas, no dudes en preguntar.

    Respondida el Dec 19, 2020 a las 14:32 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Problema:

    El código intenta agregar una lista de categorías al producto recién creado, pero la lista de categorías está vacía.

    Solución:

    Para resolver este problema, debes cargar las categorías de antemano y luego agregarlas al producto antes de guardarlo en la base de datos. Puedes hacerlo actualizando el método Create en la clase EfCoreProductRepository de la siguiente manera:

    csharp
    public override void Create(Product entity, int[] categoryIds)
    {
        using (var context = new FoodContext())
        {
            if (categoryIds != null && categoryIds.Length > 0)
            {
                var categories = context.Categories.Where(c => categoryIds.Contains(c.CategoryId)).ToList();
                entity.ProductCategories = categories.Select(c => new ProductCategory { CategoryId = c.CategoryId, ProductId = entity.ProductId }).ToList();
            }
    
            context.Set().Add(entity);
            context.SaveChanges();
        }
    }
    

    Uso:

    En el método de acción CreateProduct en tu controlador MVC, llama al método Create de la siguiente manera:

    csharp
    [HttpPost]
    public async Task CreateProduct(ProductModel model, IFormFile file)
    {
        // ... (código existente) ...
    
        if (_productService.Create(entity, model.CategoryIds))
        // ... (código existente) ...
    }
    

    Esto cargará las categorías seleccionadas y las asociará con el producto antes de insertarlo en la base de datos.

    Respondida el Dec 19, 2020 a las 14:40 - por Gemini

    Votos positivos: 0 | Votos negativos: 0