为了账号安全,请及时绑定邮箱和手机立即绑定

如何根据不同对象类型的另一个列表从数据库中获取列表?

如何根据不同对象类型的另一个列表从数据库中获取列表?

C#
白衣非少年 2021-09-19 16:21:19
我有这两个模型:public class Product{    public int Id { get; set; }    public int ProductGroupId { get; set; }    public int ProductGroupSortOrder { get; set; }    // ... some more properties    public ICollection<ProductInCategory> InCategories { get; set; }}public class ProductInCategory{    public int Id { get; set; }    public int ProductId { get; set; }    public int ProductCategoryId { get; set; }    public int SortOrder { get; set; }    // Nav.props.:    public Product Product { get; set; }    public ProductCategory ProductCategory { get; set; }}一些Products 通过属性组合在一起ProductGroupId,我希望能够Product从ProductInCategory单个 Db 查询中删除整组s 。控制器方法接收 aproduct_id和 a category_id,而不是 a ProductGroupId。对于单个Product我一直在使用此查询将其从类别中删除:ProductInCategory unCategorize = await _context.ProductsInCategories    .Where(pic => pic.ProductId == product_id && pic.ProductCategoryId == category_id)    .FirstOrDefaultAsync();进而:_context.Remove(unCategorize);await _context.SaveChangesAsync();现在,如果我有一个List<Product>要从中删除的ProductsInCategories,查询会是什么样的?我试过这个,但它在.Any()-bit上失败了:Product product = await _context.Products    .Where(p => p.Id == product_id)    .FirstOrDefaultAsync();List<Product> products = await _context.Products    .Where(g => g.ProductGroupId == product.ProductGroupId)    .ToListAsync();List<ProductInCategory> unCategorize = await _context.ProductsInCategories    .Where(pic => pic.ProductId == products.Any(p => p.Id)        && pic.ProductCategoryId == category_id)    .ToListAsync();
查看完整描述

3 回答

?
摇曳的蔷薇

TA贡献1793条经验 获得超6个赞

控制器方法接收 aproduct_id和 a category_id,而不是 aProductGroupId


第一个问题是为什么该方法product_id在需要对ProductGroupId.


这听起来很糟糕的设计,但无论如何,让我们首先将其product_id转换为所需的ProductGroupId(这将花费我们额外的数据库查询):


int? productGroupId = await _context.Products

    .Where(p => p.Id == product_id)

    .Select(p => (int?)p.ProductGroupId)

    .FirstOrDefaultAsync();


if (productGroupId == null)

{

    // Handle non existing product_id 

}

剩下的就是访问 LINQ to Entities 查询中的导航属性,EF Core 会将其转换为生成的 SQL 查询中的适当联接。不需要中间Product列表。


List<ProductInCategory> unCategorize = await _context.ProductsInCategories

    .Where(pic => pic.Product.ProductGroupId == productGroupId)

    .ToListAsync();


查看完整回答
反对 回复 2021-09-19
?
九州编程

TA贡献1785条经验 获得超4个赞

我可以建议你想要的代码修复,但有一个更好的解决方案:不加载数据以.


在您的代码示例中,您正在从数据库加载数据,然后告诉 EF 删除加载的项目。那效率不高。应该没有理由加载数据,您应该能够简单地执行查询而无需加载数据。


据我所知,实体框架不能“有条件删除”(因为没有更好的名字),例如:


DELETE FROM People WHERE Name = 'Bob' 

如果您想根据特定列值(实体的 ID 除外)删除项目,则不能依赖实体框架,除非您想加载数据(这会影响性能)。


这里有两个更好的选择:


1.自己执行SQL查询


context.Database.ExecuteSqlCommand(

        "DELETE FROM Products WHERE ProductGroupId = " + product.ProductGroupId 

      ); 

这就是我一直这样做的方式。


旁注:我期待有关 SQL 注入的评论。需要明确的是:这里没有 SQL 注入的危险,因为product.ProductGroupId它不是字符串,其值由开发人员控制,而不是最终用户。

尽管如此,我确实同意使用 SQL 参数是一种很好的做法。但是在这个答案中,我想提供一个简单的示例来展示如何执行包含 SQL 的字符串。


2. 找一个可以不用加载就删除的库。


我只是在谷歌搜索时偶然发现了这一点。实体框架扩展似乎已经实现了条件删除功能:


context.Customers.Where(x => x.ID == userId).DeleteFromQuery();

在你的情况下,那将是:


_context.Products.Where(g => g.ProductGroupId == product.ProductGroupId).DeleteFromQuery();

旁注:

我一直使用 Code First,EF 总是自动为我生成级联删除。因此,当您删除父项时,其子项也会被删除。我不确定您的数据库是否已进行级联删除,但我假设默认 EF 行为(根据我的经验)。


查看完整回答
反对 回复 2021-09-19
  • 3 回答
  • 0 关注
  • 195 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信