0

I have to entities, related to each other by orderID (one-to-many relationshoip):

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

how can I select Order from Request using linq ?

IQueryable<Request> requests = GetList();

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

I was advised to use this, but it's not working coz

select returns "IQueryable<ICollection<Order>>" type.
Hisham Aburass
  • 606
  • 1
  • 8
  • 15

2 Answers2

3

To get all Orders connected to the requests flatten out in one list, use SelectMany

var orders = requests.SelectMany(x => x.Order);
Marcus Höglund
  • 16,172
  • 11
  • 47
  • 69
0

First some introduction about how to design table relations in entity framework. Then back to your question

Table Relations in Entity Framework

Apparently there is a relation between your Requests and your Orders. This seems to be a one-to-many relation: every Order has zero or more Requests, every Requests belongs to exactly one Order using foreign key OrderId.

In entity framework the columns of your tables are represented using non-virtual properties; The relations between the tables are represented using virtual properties (virtual, because they are no real columns in your tables).

If you designed your one-to-many relationship according to the Entity Framework Code First Conventions you would have classes like:

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;}
    ...        
}

This is enough for entity framework to detect your one-to-many relationship. Your column names or table names might differ, but you get the gist. If you want different column / table names in your classes than your tables, use fluent API or attributes. See the link above.

Did you notice that the foreign key is not declared virtual: it is a real column in your table. The two virtual properties are not existing values, they describe the relation between the tables.

For every one-to-one / one-to-many / many-to-many relation the one side is described as follows:

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

The many side is described as:

// Every MyClass has zero or more YourClass objects
public virtual ICollection<YourClass> YourClasses {get; set;}

So a many-to-many has a virtual ICollection<...> on both involved classes.

Back to your Question

Having designed your table relations properly, your query will be easy. You don't have to use a join. Use the virtual relations:

Give me all (or some) Orders with all (or some) of their Requests

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(),
   });

Entity framework is smart enough to know that a (group)join is needed.

The other way round:

Give me all (or some) Requests with their Orders

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,
             ...
         }
    });

Entity Framework is smart enough to know that a join is needed

But I really like my Joins!

Well, if you really want to do design your joins yourself, you can do the following:

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,
        });

Consider a more readable solution by splitting the Order and Request properties:

(order, request) => new
{
     Order = new
     {
         Id = order.Id,
         Name = order.Name,
     },
     Request = new
     {
          Id = request.Id,
          Name = request.Name,
     },
})

If you want an Order with its Requests, use a GroupJoin instead of a Join

var result = dbContext.Orders
    .GroupJoin(dbContext.Requests,  // GroupJoin Orders with Requests
        order => order.Id,          // from every Order take the Id
        request => request.OrderId, // from every Request take the OrderId
        (order, requests) => new    // when they match, take the order and 
        {                           // all matching requests to make one new object
            ...
        })
Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116