【问题标题】:Linq query (sql to linq)linq 查询(sql 到 linq)
【发布时间】:2012-11-20 07:59:53
【问题描述】:

拥有三个表(Item、Purchase、PurchaseItem),我正在尝试编写一个 linq 查询来查找一个项目包含多少有效购买。

在标准 SQL 中,我会使用带有计数的子查询,但我似乎无法获得 linq 查询来执行此操作。

SQL:

select i.name, 
InTrade = (select count(*) from Purchase p join PurchaseItem pi on p.id = pi.PurchaseId where p.Isvalid = 1 and pi.ItemId = i.Id)
from Item i

林克:

from i in Items select new 
{
    i.Name,
    InTrade = from pi in PurchaseItems where pi.ItemId == i.ID
        select new 
            {
                pi,
                Purchase = from p in Purchases where p.ID == pi.PurchaseId
                select new { p }
            }
}

这里我试图在一个查询中检索我的所有数据,我可能需要另一个查询才能真正得到我想要的。使用这种方法,我可能会走上一条麻烦的道路,所以也许有人可以阐明在 linq 中实现这一目标的“最佳实践”。

我为这个例子准备了一些测试数据:

if exists (select * from sysobjects where name = 'PurchaseItem') drop table PurchaseItem
if exists (select * from sysobjects where name = 'Item') drop table Item
if exists (select * from sysobjects where name = 'Purchase') drop table Purchase
go

create table Item
(
    ID int not null primary key,
    Name nvarchar(30) not null
)

create table Purchase
(
    ID int not null primary key,    
    Name nvarchar(30) not null,
    ConfirmedDate datetime,
    Isvalid bit not null
)

create table PurchaseItem
(
    ID int not null primary key,
    PurchaseId int null references Purchase(ID),
    ItemId int null references Item(ID)
)

insert Item values (1, 'Bread')
insert Item values (2, 'Beer')
insert Item values (3, 'Wine')
insert Item values (4, 'Milk')
insert Item values (5, 'Apple')
insert Item values (6, 'Steak')
insert Item values (7, 'Hamburger')
insert Item values (8, 'Vinegar')

insert Purchase values (1, 'Purchase 1', null, 1)
insert Purchase values (2, 'Purchase 2', null, 0)
insert Purchase values (3, 'Purchase 3', '2008-1-7', 1)

insert PurchaseItem values (1, 1, 1)
insert PurchaseItem values (2, 1, 2)
insert PurchaseItem values (3, 1, 3)
insert PurchaseItem values (4, 1, 4)
insert PurchaseItem values (5, 1, 5)
insert PurchaseItem values (6, 1, 6)
insert PurchaseItem values (7, 2, 2)
insert PurchaseItem values (8, 3, 2)
insert PurchaseItem values (9, 3, 1)
insert PurchaseItem values (10, 3, 5)

【问题讨论】:

  • 您的购买是双向映射的吗?意思是,PurchaseItem 有一个 List 作为属性。如果是这种情况,您可能可以简化很多。
  • 不,它目前没有像那样映射。一种方法可能是对我的第一个实体执行 .ToList() ,然后对每个实体执行一个并逐个实体填充它。虽然我希望尽可能长时间地让所有内容都可以查询
  • 迭代可能不是一个好主意,因为您将向数据库发出一堆查询,而这可以用一个来完成。如果你有双向关系,你就不必通过 id 和类似的东西加入。有几种不同的方法,我会看看是否可以发布一些供您尝试。然后您可以跟踪 SQL 以确保它只发出一个查询。
  • 是的,你可能是对的,迭代不是最好的方法。我已经开始从“子查询”重写 linq 以加入。也许这会更容易。
  • 我刚刚发布了一些您可以尝试的不同替代方案。我通常尽量避免手动连接,因为这是 ORM 的全部目的,通过让实体具有真实关系来避免手动工作。

标签: linq linq-to-sql


【解决方案1】:

我认为您可以通过几种方法来完成此操作,只需对数据库进行一次查询即可。以下是我能想到的两个:

使用商品与其购买之间的双向关联:

var resultUsingSubItems = context.PurchaseItems.Select(x => new
    {
        Item = x,
        ValidPurchases = x.Purchases.Count(y => y.IsValid)
    });

还有另一种方法,按项目分组:

var resultUsingGrouping = context.Purchases.GroupBy(x => x.Item).Select(
        g => new
            {
                Item = g.Key,
                ValidPurchases = g.Count(y => y.IsValid)
            });

请使用SQL profiler 确保 Linq2SQL 将其转换为单个 SQL 查询。

【讨论】:

  • 谢谢,.. 我会看看你的两个例子。明天应该可以将结果发布回来,因为我今天已经受够了 linq :) 再次感谢
【解决方案2】:

您也可以这样做:

var results = from i in db.Items
              select new InTradeResult
              {
                ProductName = i.Name,
                InTradeCount = i.PurchaseItems.Count(pi => pi.Purchase.IsValid)
              };

这是一个显示结果的示例控制台应用程序:

class Program
{
  static void Main(string[] args)
  {
    using (var db = new Context())
    {
      var results = from i in db.Items
                    select new InTradeResult
                    {
                      ProductName = i.Name,
                      InTradeCount = i.PurchaseItems.Count(pi => pi.Purchase.IsValid)
                    };

      foreach (var result in results)
      {
        System.Console.WriteLine("{0} - {1}", result.InTrade, result.ProductName);
      }

      System.Console.ReadKey();
    }
  }
}

public class InTradeResult
{
  public string ProductName { get; set; }
  public int InTradeCount { get; set; }
}

public class Context : IDisposable
{
  public IList<Item> Items { get; set; }
  public IList<Purchase> Purchases { get; set; }
  public IList<PurchaseItem> PurchaseItems { get; set; }

  public Context()
  {
    Items = new List<Item>();
    Items.Add(new Item { ID = 1, Name = "Bread" });
    Items.Add(new Item { ID = 2, Name = "Beer" });
    Items.Add(new Item { ID = 3, Name = "Wine" });
    Items.Add(new Item { ID = 4, Name = "Milk" });
    Items.Add(new Item { ID = 5, Name = "Apple" });
    Items.Add(new Item { ID = 6, Name = "Steak" });
    Items.Add(new Item { ID = 7, Name = "Hamburger" });
    Items.Add(new Item { ID = 8, Name = "Vinegar" });

    Purchases = new List<Purchase>();
    Purchases.Add(new Purchase { ID = 1, Name = "Purchase 1", ConfirmedDate = null, IsValid = true });
    Purchases.Add(new Purchase { ID = 2, Name = "Purchase 2", ConfirmedDate = null, IsValid = false });
    Purchases.Add(new Purchase { ID = 3, Name = "Purchase 3", ConfirmedDate = null, IsValid = true });

    PurchaseItems = new List<PurchaseItem>();
    PurchaseItems.Add(new PurchaseItem(1, Purchases[0], Items[0]));
    PurchaseItems.Add(new PurchaseItem(2, Purchases[0], Items[1]));
    PurchaseItems.Add(new PurchaseItem(3, Purchases[0], Items[2]));
    PurchaseItems.Add(new PurchaseItem(4, Purchases[0], Items[3]));
    PurchaseItems.Add(new PurchaseItem(5, Purchases[0], Items[4]));
    PurchaseItems.Add(new PurchaseItem(6, Purchases[0], Items[5]));
    PurchaseItems.Add(new PurchaseItem(7, Purchases[1], Items[1]));
    PurchaseItems.Add(new PurchaseItem(8, Purchases[2], Items[1]));
    PurchaseItems.Add(new PurchaseItem(9, Purchases[2], Items[0]));
    PurchaseItems.Add(new PurchaseItem(10, Purchases[2], Items[4]));
  }

  public void Dispose()
  {
    //Do nothing
  }
}


public class Item
{
  public int ID { get; set; }
  public string Name { get; set; }

  public IList<PurchaseItem> PurchaseItems { get; set; }

  public Item()
  {
    PurchaseItems = new List<PurchaseItem>();
  }
}

public class Purchase
{
  public int ID { get; set; }
  public string Name { get; set; }
  public DateTime? ConfirmedDate { get; set; }
  public bool IsValid { get; set; }

  public IList<PurchaseItem> PurchaseItems { get; set; }

  public Purchase()
  {
    PurchaseItems = new List<PurchaseItem>();
  }
}

public class PurchaseItem
{
  public int ID { get; set; }

  public int PurchaseId { get; set; }
  public Purchase Purchase { get; set; }

  public int ItemId { get; set; }
  public Item Item { get; set; }

  public PurchaseItem(int id, Purchase purchase, Item item)
  {
    ID = id;

    PurchaseId = purchase.ID;
    Purchase = purchase;
    purchase.PurchaseItems.Add(this);

    ItemId = item.ID;
    Item = item;
    item.PurchaseItems.Add(this);
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-12
    • 1970-01-01
    • 1970-01-01
    • 2016-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多