我有以下两种模型:
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; }
}
有些Product
通过属性ProductGroupId
分组在一起,我希望能够从Product
中一次删除整组ProductInCategory
数据库查询。
控制器方法接收product_id
和category_id
,而不是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()
位上却失败了:
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();
答案 0 :(得分:2)
控制器方法接收
product_id
和category_id
,而不是ProductGroupId
第一个问题是,为什么该方法需要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();
答案 1 :(得分:1)
尝试更改为以下内容:
Mail::to("xyz.gmail.com")->send(new contactMailAdmin($userData));
答案 2 :(得分:1)
我可能会针对您想要的内容提出代码修复建议,但是有一个更好的解决方案:n 从加载数据开始。
在您的代码示例中,您要从数据库加载数据,然后告诉EF删除加载的项目。那不是很有效。应该没有理由加载数据,您应该能够简单地执行查询而无需加载数据。
据我所知,Entity Framework无法“条件删除”(因为缺少更好的名称),例如:
DELETE FROM People WHERE Name = 'Bob'
如果要基于特定的列值(实体的ID除外)删除项目,则除非依赖于加载数据(这会降低性能),否则不能依赖Entity Framework。
这里有两个更好的选择:
1。自己执行SQL查询
context.Database.ExecuteSqlCommand(
"DELETE FROM Products WHERE ProductGroupId = " + product.ProductGroupId
);
这就是我一直这样做的方式。
旁注:我期待有关SQL注入的评论。需要明确的是:这里没有SQL注入的危险,因为
product.ProductGroupId
不是字符串,并且其值是由开发人员而不是最终用户控制的。
但是,我确实同意使用SQL参数是一种好习惯。但是在这个答案中,我想提供一个简单的示例来展示如何执行包含SQL的字符串。
2。找到一个可以删除而不加载的库。
我只是在谷歌搜索时才偶然发现这一点。 Entity Framework Extensions似乎已经实现了条件删除功能:
context.Customers.Where(x => x.ID == userId).DeleteFromQuery();
在您的情况下,应该是:
_context.Products.Where(g => g.ProductGroupId == product.ProductGroupId).DeleteFromQuery();
边注:
我一直使用代码优先,并且EF总是自动为我生成级联删除。因此,删除父级时,其子级也会被删除。我不确定您的数据库是否具有级联的删除操作,但是我假设是默认的EF行为(根据我的经验)。
答案 3 :(得分:0)
在先前的LINQ查询中,products
值可能设置为null。添加另一个条件来验证这一点。
.Where(pic => products && pic.ProductId == products.Any(p => p.Id)
&& pic.ProductCategoryId == secondary_id)