转换-SQL到LINQ

时间:2019-01-03 10:26:28

标签: c# sql linq sql-to-linq-conversion

如何使用LINQ

完成以下操作
SELECT r.BrandID 
FROM dbo.Items AS r
JOIN Brands AS d ON r.BrandID = d.BrandID
WHERE CategoryID IN (SELECT CategoryID 
                     FROM dbo.Categories
                     WHERE Name = 'Bread - Bakery')

Brand类的代码:

public class Brand
{
    public int BrandID { get; set; }
    [DisplayName("Brand Name")]
    public string Name { get; set; }
    public virtual List<Category> Categories { get; set; }
    public virtual List<Item> Items { get; set; }
}

Item类的代码:

public class Item
{
    [Key]
    public int ItemID { get; set; }
    public virtual Category Category { get; set; }
    public virtual Brand Brand { get; set; }
    public int CategoryID { get; set; }
    public int BrandID { get; set; }
}

Category类的代码:

public class Category
{
    [Key]
    public int CategoryID { get; set; }
    [DisplayName("Category Name")]
    public virtual string Name { get; set; }
    public virtual List<Brand> Brands { get; set; }
    public virtual List<Item> Items { get; set; }
}

2 个答案:

答案 0 :(得分:1)

dbContext.Items
  .Where(x => x.Category.Name.Equals("Bread - Bakery"))
  .Select(x => x.BrandID);

我不确定为什么需要使用以下联接。似乎并不需要(除非有意与品牌进行内部合作以从商品中删除不匹配的记录)

JOIN Brands AS d ON r.BrandID = d.BrandID

答案 1 :(得分:0)

嗯,可惜您没有写您的要求,现在我必须从您的SQL代码中猜测它们是什么。

因此,您有一个包含BrandsItemsCategories的数据库。每个Item都有一个Category,每个Category可以被零个或多个Items使用:一对多关系

每个Item都具有某个Brand,每个Brand可以具有零个或多个项目:也是直接的一对多关系。

最后,每个Brand的零个或多个Categories,每个Category的零个或多个Brands:多对多

现在,您收集Items的集合,只想保留具有Items等于Name的类别的Bread - Bakery。从其余项目中,您需要所有其BrandId。

要求为:“给我所有BrandIds中的Items中的Category,其中Name等于“面包-面包店”。

如果使用实体框架,则通常使用virtual ICollection而不是自己进行联接会更容易。实体框架知道表之间的关系,并将为其构成适当的联接。

var result = myDbContext.Items                             // from the collection of Items
    .Where(item => item.Category.Name == "Bread - Bakery") // keep only those with a Category
                                                           // that has a Name equal to ...
    .Select(item.BrandId);                        // from the remaining items select the BrandId

如果您确实想要,并且可以说服项目负责人确保不信任实体框架进行正确的联接,则可以自己进行联接:

// get the sequence of categories that I'm interested in:
var breadBakeryCategories = myDbContext.Categories
    .Where(category => category.Name == "Bread - Bakery");

// join the items with these categories
// and select the BrandIds
var requestedBrandIds= myDbContext.Items
    .Join(breadBakeryCategories,
    item => item.CategoryId,           // from every Item take the CategoryId,
    category => category.CategoryId,   // from every Category take the CategoryId
    (item, category) => item.BrandId);   // when they match, select the BrandId

TODO:考虑将其合并为一条大的丑陋的LINQ语句。

备注1

您确实意识到您的结果可能多次具有相同的BrandId,不是吗?

如果您不想这么做,请从品牌开始:

var result = myDbContext.Brands
.Where(brand => brand.Items.Select(item => item.Category.Name)
                .Where(name => name == "Bread - Bakery")
                .Any())
.Select(brand => brand.brandId);

换句话说:从品牌集合中,仅保留名称至少等于“面包-面包店”的至少一个类别的那些品牌。从其余的品牌中选择BrandId。

**备注2 **

为什么您的一对多列表而不是ICollections?您确定brand.Categories[4]的含义正确吗?

var result = myDbContext.Brands
    .Where(brand => brand.Category[4].Name == "Bread - Bakeries");

您的编译器不会抱怨,但是您会遇到运行时错误。

请考虑将virtual ICollection<...>用于一对多和多对多关系。这样,您将完全拥有数据库表所需的功能,并且如果您尝试使用无法转换为SQL的功能,则编译器会抱怨