c# EF core Удаление главной сушности и всех связанных с ней
Доброго времени суток Есть модель каталога
namespace Market.Model.CatalogFolder
{
public class Category
{
public int CategoryId { get; set; }
/// <summary>
///Название категории
/// </summary>
public string? Name { get; set; } = null!;
/// <summary>
///Товар в категории
public List<Product> Product { get; set; } = new();
public List<Sub_Category> Sub_Category { get; set; } = new();
}
}
И модель товара
namespace Market.Model.CatalogFolder
{
public class Product
{
public int ProductId { get; set; }
/// <summary>
///Название товара
/// </summary>
public string? Name { get; set; } = null!;
/// <summary>
///Цена товара
/// </summary>
public double Price { get; set; }
/// <summary>
///Описание товара
/// </summary>
public string? Description { get; set; } = null!;
/// <summary>
///Инстуркция использования товара
/// </summary>
public string? Instruction { get; set; } = null!;
/// <summary>
///Тип файла txt
/// </summary>
public bool TypeTxt { get; set; } = false;
/// <summary>
///Тип файла => цельный файл
/// </summary>
public bool TypeFile { get; set; } = false;
public List<Catalog?> Catalog { get; set; } = new List<Catalog?>();
public List<Category?> Category { get; set; } = new List<Category?>();
public List<Sub_Category?> Sub_Category { get; set; } = new List<Sub_Category?>();
public List<Product_File> Product_File { get; set; } = new();
}
}
При удалении удаляется каталог и все связи в промежуточной таблице, но товары все остаются, то есть товары не удаляются, подскажите как удалить категорию и все связанные с ней товары. Этот код не работает у меня
var category = db.Category.Include(x => x.Name == "Категория").ToList();
db.RemoveRange(category);
db.SaveChanges();
Этим кодом я могу удалить что хочу, но тогда присутствие ключей в моделях, не много теряют смысл
var categories = db.Category.Include(x => x.Product)
.Where(x => x.Name == Name).ToList();
var products = db.Product.Include(x => x.Category).Where(x => x.Category
.Any(x => x.Name == Name)).ToList();
if(categories.Count() > 0)
db.RemoveRange(categories);
if(products.Count() > 0)
db.RemoveRange(products);
db.SaveChanges();
using Microsoft.EntityFrameworkCore;
using VIPMarket.Model.AdminModel;
using VIPMarket.Model.CatalogFolder;
using VIPMarket.Model.UserModel.BuyProductFolder;
using VIPMarket.Model.UserModel.Referal;
namespace Market
{
public class DataContext : DbContext
{
public DbSet<Model.AdminModel.Admin> Admin { get; set; } = null!;
public DbSet<Model.UserModel.User> User { get; set; } = null!;
public DbSet<Referal_LVL1> Referal_LVL1 { get; set; } = null!;
public DbSet<Referal_LVL2> Referal_LVL2 { get; set; } = null!;
public DbSet<Master> Master { get; set; } = null!;
public DbSet<Statistics> Statistics { get; set; } = null!;
public DbSet<PromoDB> PromoDB { get; set; } = null!;
public DbSet<BuyProduct> BuyProduct { get; set; } = null!;
public DbSet<ConfigBot> ConfigBot { get; set; } = null!;
public DbSet<Category> Category { get; set; } = null!;
public DbSet<Catalog> Catalog { get; set; } = null!;
public DbSet<Sub_Category> Sub_Category { get; set; } = null!;
public DbSet<Product> Product { get; set; } = null!;
public DbSet<Product_File> Product_File { get; set; } = null!;
protected readonly IConfiguration Configuration;
public DataContext(IConfiguration configuration)
{
Configuration = configuration;
}
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.UseSqlite(Configuration.GetConnectionString("DB"));
}
}
}
Ответы (2 шт):
Вам нужно создать в товарах внешний ключ с указанием на Id Категории, что бы средствами EF Core, в базе данных была связана связь "один ко многим". Попробуйте изменить описание моделей Товаров и Категорий, а затем создайте миграцию и проконтролируйте что в ней явно указан признак каскадного удаления.
Модель Товара
- Удалите сначала эти свойства из модели Товара:
public List<Catalog?> Catalog { get; set; } = new List<Catalog?>();
public List<Category?> Category { get; set; } = new List<Category?>();
public List<Sub_Category?> Sub_Category { get; set; } = new List<Sub_Category?>();
public List<Product_File> Product_File { get; set; } = new();
- И попробуйте, сначала создать внешний ключ только для категории:
[ForeingKey("Category")]
public int CategoryId {get; set;}
public Category Category{get; set;}
Удалите вручную все существующие записи в базе данных в этих двух таблицах, что бы не было проблем с миграцией
В модели Category удалите вот эти свойства:
public List Product { get; set; } = new();
public List<Sub_Category> Sub_Category { get; set; } = new();Создайте новую миграцию
Проверьте код миграции, в которой должны быть строки с созданием внешнего ключа в таблице с Товарами, но не Категориями. А также при добавлении этого внешнего ключа, должна быть сгенерирована строка по умолчанию, что то типа...
onDelete: ReferentialAction.Cascade;Таким образом при удалении Категории, будут также удаляться все Товары, со ссылкой на эту категорию. И здесь можно вручную изменить опции для удаления, так как такая миграция еще не передавалась в базу данных.Попробуйте обновить базу через команду update-data
Если миграция прошла успешно, то проверьте результат в базе данных.
По аналогии добавляйте внешние ключи со ссылками на субкатегории и так далее..
Учебный пример с созданием Категорий и Товаров для интернет магазина на ASP.NET MVC можно посмотреть на видео.
Код который решил проблему
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EF_Core_Test
{
public class Catalog
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Category> Category { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EF_Core_Test
{
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public int CatalogId { get; set; }
public Catalog Catalog { get; set; }
public ICollection<Product> Product { get; set; }
public ICollection<Sub_Category>? Sub_Category { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EF_Core_Test
{
public class Sub_Category
{
public int Id { get; set; }
public string Name { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
public ICollection<Product> Product { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EF_Core_Test
{
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
[ForeignKey("Category")]
public int CategoryId { get; set; }
public Category Category { get; set; }
[ForeignKey("Catalog")]
public int CatalogId { get; set; }
public Catalog Catalog { get; set; }
[ForeignKey("Sub_Category")]
public int? Sub_CategoryId { get; set; }
public Sub_Category? Sub_Category { get; set; } //Если свойство может иметь null значение, то Sub_CategoryId тоже должен принимать null значение
}
}
using Microsoft.EntityFrameworkCore;
namespace EF_Core_Test
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
using (DataContext db = new DataContext())
{
db.Database.EnsureCreated();
lock (this)
db.SaveChanges();
}
}
private void button2_Click(object sender, EventArgs e)
{
using (DataContext db = new DataContext())
{
Catalog catalog = new Catalog()
{
Name = "Каталог"
};
db.AddRange(catalog);
Category category = new()
{
Name = "Категория",
Catalog = catalog
};
db.AddRange(category);
Sub_Category sub_Category = new()
{
Name = "Под категория Exist",
Category = category
};
Product product = new()
{
Name = "Товар",
Catalog = catalog,
Category = category,
Sub_Category = sub_Category
};
db.Product.AddRange(product);
lock (this)
db.SaveChanges();
}
}
private void button3_Click(object sender, EventArgs e)
{
using(DataContext db = new DataContext())
{
db.Remove(db.Catalog.FirstOrDefault());
db.SaveChanges();
}
}
private void button4_Click(object sender, EventArgs e)
{
using (DataContext db = new DataContext())
{
Product product = new()
{
Name = "Товар",
Catalog = db.Catalog.FirstOrDefault(),
Category = db.Category.FirstOrDefault(),
};
db.Product.AddRange(product);
db.SaveChanges();
}
}
private void button5_Click(object sender, EventArgs e)
{
using (DataContext db = new DataContext())
{
//Удаляем все категорию и все связанные с ней сушности
db.Remove(db.Product.OrderBy(x => x.Category).Include(x => x.Category).LastOrDefault());
db.SaveChanges();
}
}
private void button6_Click(object sender, EventArgs e)
{
///Создаем под категорию и товар в ней
using (DataContext db = new DataContext())
{
Sub_Category sub_Category = new()
{
Name = "Под категория",
Category = db.Category.FirstOrDefault()
};
Product product = new()
{
Name = "Товар sub_Category",
Catalog = db.Catalog.FirstOrDefault(),
Category = db.Category.FirstOrDefault(),
Sub_Category = sub_Category
};
db.Product.AddRange(product);
db.SaveChanges();
}
}
private void button7_Click(object sender, EventArgs e)
{
using (DataContext db = new DataContext())
{
//Выводим количество товар под категории
MessageBox.Show(db.Product.Include(x => x.Sub_Category).Where(x => x.Sub_Category.Name == "Под категория").ToList().Count().ToString());
}
}
}
}