【问题标题】:query and create objects with a one to many relationship using LINQ使用 LINQ 查询和创建具有一对多关系的对象
【发布时间】:2013-12-18 22:30:02
【问题描述】:

在数据库中,我有两个具有一对多关系的表:

orders          suborders
-----------     -----------
id              id
name            order_id
                name

我想查询这些表并最终得到一个订单对象列表,其中每个对象都包含一个子订单对象列表(或空列表)。我还想在单个数据库查询中执行此操作,以使其表现良好。

在传统的 SQL 查询领域,我会做类似的事情(原谅伪代码):

rs = "select o.id, o.name, so.id, so.name from orders o left join suborders so on o.id = so.order_id order by o.id"

orders = new List<Order>
order = null
foreach (row in rs) {
    if (order == null || row.get(o.id) != order.id) {
        order = new Order(row.get(o.id), row.get(o.name), new List<Suborders>)   
        orders.add(order)
    }    

    if (row.get(so.id) != null) {
        order.suborders.add(new Suborder(row.get(so.id) row.get(so.name))
    }
}

有没有办法使用 LINQ-to-Entities 获得相同的结果对象结构?请注意,我想从查询中获取新对象,而不是实体框架生成的对象。

以下内容让我很接近,但引发异常:“LINQ to Entities 无法识别该方法...”

var orders = 
    (from o in Context.orders
     join so in Context.suborders on o.id equals so.order_id into gj
     select new Order 
     {
         id = o.id,
         name = o.name,
         suborders = (from so in gj select new Suborder
         {
             so.id,
             so.name
         }).ToList()
     }).ToList();

【问题讨论】:

  • 没有。我不想要内连接,我的查询是左连接。我还专门寻找创建具有 DB 结构具有的一对多关系的对象列表的方法。仅仅做一个连接不会让我明白这一点。
  • @MikeRoberts 你应该标记 EntityFramework 或 LinqToSQL

标签: c# linq entity-framework linq-to-entities


【解决方案1】:

解决方案最终非常简单。关键是使用组连接让 SQL 对子订单进行左连接,并添加第二个 ToList() 调用以强制运行查询,这样您就不会尝试在 SQL 服务器上创建对象。

orders = Context.orders
    .GroupJoin(
        Context.suborders,
        o => o.id,
        so => so.order_id,
        (o, so) => new { order = o, suborders = so })
    .ToList()
    .Select(r => new Order
    {
        id = r.order.id,
        name = r.order.name,
        suborders = r.suborders.Select(so => new Suborder
        {
            id = so.id,
            name = so.name
        }.ToList()
    }).ToList();

此代码仅针对所有对象及其子对象对 SQL 进行一次查询。它还允许您将 EF 对象转换为您需要的任何对象。

【讨论】:

    【解决方案2】:

    我总是为关系创建一个虚拟化属性

    所以只需扩展(添加属性)到您的订单类:

      public class Order{
      ...
    
      List<Suborder> _suborders;
    
      public List<Suborder> Suborders{
      get {
            return _suborders ?? (_suborders = MyContext.Suborders.Where(X=>X.order_id==this.id).ToList());
           }
      ...
      }
    

    只有在调用 getter 时才会获取(拉取)数据

    【讨论】:

    • 这不会仍然导致向数据库发送多个查询吗?这主要是我试图阻止的,所以我可以保持良好的表现。
    • 不,当您查询订单时,它不会查询子订单,只有当您使用 mylist=myorder.SubOrders 之类的东西时,才会从数据库中读取
    【解决方案3】:

    这段代码怎么样?

    你可以得到一个本地缓存。

    List<Orders> orders = new List<Orders>();
    
    private void UpdateCache(List<int> idList)
    {
        using (var db = new Test(Settings.Default.testConnectionString))
        {
            DataLoadOptions opt = new DataLoadOptions();
            opt.LoadWith<Orders>(x => x.Suborders);
            db.LoadOptions = opt;
            orders = db.Orders.Where(x => idList.Contains(x.Id)).ToList();
        }
    }
    
    private void DumpOrders()
    {
        foreach (var order in orders)
        {
            Console.WriteLine("*** order");
            Console.WriteLine("id:{0},name:{1}", order.Id, order.Name);
    
            if (order.Suborders.Any())
            {
                Console.WriteLine("****** sub order");
    
                foreach (var suborder in order.Suborders)
                {
                    Console.WriteLine("\torder id:{0},id{1},name:{2}", suborder.Order_id, suborder.Id, suborder.Name);
                }
            }
        }
    }
    
    private void button1_Click(object sender, EventArgs e)
    {
        UpdateCache(new List<int> { 0, 1, 2 });
        DumpOrders();
    }
    

    下面的输出示例

    *** order
    id:0,name:A
    ****** sub order
        order id:0,id0,name:Item001
        order id:0,id1,name:Item002
        order id:0,id2,name:Item003
    *** order
    id:1,name:B
    ****** sub order
        order id:1,id0,name:Item003
    *** order
        id:2,name:C
    ****** sub order
        order id:2,id0,name:Item004
        order id:2,id1,name:Item005
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-08
      • 2013-02-17
      • 2017-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-25
      相关资源
      最近更新 更多