如何使用Linq从另一个实体中选择实体?

时间:2018-08-16 05:16:50

标签: c# entity-framework linq

我必须要有实体,这些实体通过orderID(一对多Relationshiphoip)彼此关联:

Request                                       Order
-reqID                                      -orderID**
-orderID**                                  -name
-name

如何使用linq从“请求”中选择“订单”?

IQueryable<Request> requests = GetList();

IQueryable<Order> orders = requests.Select(x => x.Order);

建议我使用此功能,但不能正常工作

select returns "IQueryable<ICollection<Order>>" type.

2 个答案:

答案 0 :(得分:3)

要使所有与订单关联的订单在一个列表中变平,请使用SelectMany

var orders = requests.SelectMany(x => x.Order);

答案 1 :(得分:0)

首先介绍如何在实体框架中设计表关系。然后回到您的问题

实体框架中的表关系

很显然,您的RequestsOrders之间存在某种关系。这似乎是一对多关系:每个Order具有零个或多个Requests,每个Requests都使用外键{{1}恰好属于一个Order }。

在实体框架中,表的列是使用非虚拟属性表示的;表之间的关系使用虚拟属性表示(虚拟,因为它们在表中不是真实的列)。

如果您根据Entity Framework Code First Conventions设计一对多关系,您将拥有类似这样的类:

OrderId

这足以使实体框架检测到您的一对多关系。您的列名或表名可能会有所不同,但是您的主旨是。如果您要在类中使用与表不同的列/表名称,请使用流利的API或属性。请参阅上面的链接。

您是否注意到外键未声明为虚拟键:它是表中的实列。这两个虚拟属性不是现有值,它们描述了表之间的关系。

对于每个一对一/一对多/多对多关系,class Order { public int Id {get; set;} // every order has zero or more requests (one-to-many) public virtual ICollection<Request> Requests {get; set;} public string Name {get; set;} ... } class Request { public int Id {get; set;} // Every Request belongs to exactly one Order using foreign key public int OrderId {get; set;} public virtual Order Order {get; set;} public string Name {get; set;} ... } 面描述如下:

one

// Every MyClass object belongs to exactly one YourClass object using foreign key: public int YourClassId {get; set;} public virtual YourClass YourClass {get; set;} 面描述为:

many

因此在涉及的两个类中,多对多都有// Every MyClass has zero or more YourClass objects public virtual ICollection<YourClass> YourClasses {get; set;}

返回您的问题

已经正确设计了表关系,您的查询将很容易。您不必使用联接。使用虚拟关系:

将所有(或部分)请求(全部或部分)发给我

virtual ICollection<...>

实体框架足够聪明,可以知道需要(组)连接。

反过来:

将所有(或部分)请求与他们的订单一起给我

var result = dbContext.Orders
   .Where(order => ...)            // give me only the orders that ...
   .Select(order => new            // from every remaining order make one new object
   {                               // select only the properties you plan to use
        Id = order.Id,
        Name = order.Name,
        ...
        Requests = order.Requests
           .Where(request => ...)   // give me only the requests that ...
           .Select(request => new
           {                        // again: select only the properties you plan to use
                Id = request.Id,
                Name = request.Name,
                ...
                // not needed: OrderId = request.OrderId, you already know the value!
           })
           .ToList(),
   });

实体框架足够聪明,可以知道需要联接

但是我真的很喜欢我的加入!

好吧,如果您真的想自己设计联接,则可以执行以下操作:

var result = dbContext.Requests
    .Where(request => ...)        // take only the requests that ...
    .Select(request => new        // from every remaining request make one new object
    {                             // with only the properties you plan to use
         Id = request.Id,
         Name = request.Name,
         Order = new               // from the one and only Order of this Request
         {                         // take only the properties you plan to use
             Name = request.Order.Name,
             ...
         }
    });

通过拆分Order和Request属性来考虑一种更具可读性的解决方案:

var result = dbContext.Orders
    .Join(dbContext.Requests,       // Join Orders with Requests
        order => order.Id,          // from every Order take the Id
        request => request.OrderId, // from every Request take the OrderId
        (order, request) => new     // when they match, take the order and the request
        {                           // to make a new object with properties
             OrderId = order.Id,
             OrderName = order.Name,
             RequestName = request.Name,
        });

如果您想要(order, request) => new { Order = new { Id = order.Id, Name = order.Name, }, Request = new { Id = request.Id, Name = request.Name, }, }) ,请使用Order with its Requests代替GroupJoin

Join