Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework Linq SelectMany with condition

I have been trying for a while to find a suitable solution for a linq query I am trying to write.

In my model structure I have my Item class, which holds a list of PaymentRecords. What I want my query to achieve is:

public class PaymentRecord
{
    public int PaymentRecordId { get; set; }

    [Required]
    public double PaymentAmount { get; set; }

    [Required]
    public DateTime DateOfPayment { get; set; }

    [Required]
    public bool FinalPayment { get; set; }

    [JsonIgnore]
    public Item Item{ get; set; }
}

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

    public List<PaymentRecord> PaymentRecords {get; set;}

    ...various other properties
}   

Select all Items, where the PaymentRecord list matches the condition below (which works fine), or where PaymentRecord is null e.g. the Items class has no PaymentRecord. Is there a way in which to do this?

var result = m_context.Item
            .SelectMany(
                x => x.PaymentRecords.Where(p => (p.FinalPayment == true
                                              && p.DateOfPayment >= _revenueStatementRequest.StartDate
                                              && p.DateOfPayment <= _revenueStatementRequest.EndDate)
                                              || p.FinalPayment != true),
                (x, p) => x
            )
            .ToList();

Ideally I would like to do something like below, but I have not been able to get anything similar to work:

var result = m_context.Item
            .SelectMany(
                x => x.PaymentRecords.Where(p => (p.FinalPayment == true
                                              && p.DateOfPayment >= _revenueStatementRequest.StartDate
                                              && p.DateOfPayment <= _revenueStatementRequest.EndDate)
                                              || p.FinalPayment != true)
                || x.PaymentRecords == null,
                (x, p) => x
            )
            .ToList();

After working from the answer given I have this:

 m_context.Item.Where(c => (!
                            c.PaymentRecords.Any(q => (q.FinalPayment &&
                                                            q.DateOfPayment >= _revenueStatementRequest.StartDate &&
                                                            q.DateOfPayment <= _revenueStatementRequest.EndDate)
                                                            || q.FinalPayment != true
                                                )
                            )
                    && (c..Type == Booked || c.Type == Reserved)
                    && (c.StartDate < _revenueStatementRequest.StartDate)
                    )
like image 803
Thewads Avatar asked Mar 14 '13 13:03

Thewads


People also ask

What is select () and SelectMany () in Linq?

Select and SelectMany are projection operators. A select operator is used to select value from a collection and SelectMany operator is used to selecting values from a collection of collection i.e. nested collection.

Can SelectMany return null?

SelectMany experiences a NullReferenceException when selector returns null . This is undesirable because it's a confusing crash with a "forbidden" exception type in BCL code.

What best describes the SelectMany () Language Integrated Query LINQ extension method?

What best describes the SelectMany() Language Integrated Query (LINQ) extension method? It projects each element of a sequence to an IEnumerable<T> and flattens the resulting sequences into one sequence.

What is SelectMany?

SelectMany(<selector>) method The SelectMany() method is used to "flatten" a sequence in which each of the elements of the sequence is a separate, subordinate sequence.


2 Answers

You could do it without the SelectMany

        List<Item> res = m_context.Items
                      .Where(c => !c.PaymentRecords
                                .Any(q => (q.FinalPayment && 
                                        q.DateOfPayment >=_revenueStatementRequest.StartDate &&
                                        q.DateOfPayment <= _revenueStatementRequest.EndDate)
                                        || !q.FinalPayment)
                            )
    //**EDIT**
    .Where(c => c.StartDate < _revenueStatementRequest.StartDate)
 //this is comment out, so we can better test on the more complex part of the query
  //.Where(c => c.Type == Booked || c.Type == Reserved)   
    .ToList();

that way you get a List<Item> instead of List<PaymentRecord>

like image 106
Jens Kloster Avatar answered Nov 11 '22 04:11

Jens Kloster


Select all Items, where the PaymentRecord list matches the condition below (which works fine), or where PaymentRecord is null e.g. the Items class has no PaymentRecord.

var result = m_context.Item
                      .Where(x => !x.PaymentRecords.Any() ||
                                   x.PaymentRecords.Any(p => (p.FinalPayment == true
                                                        && p.DateOfPayment >= _revenueStatementRequest.StartDate
                                                        && p.DateOfPayment <= _revenueStatementRequest.EndDate)
                                                        || p.FinalPayment != true))
                      .ToList();

I don't see any reason for using SelectMany here. Simple Where condition can do the work.

like image 1
MarcinJuraszek Avatar answered Nov 11 '22 05:11

MarcinJuraszek