Home > Blockchain >  Ef Core 7, how to get one latest message per customer with take and skip
Ef Core 7, how to get one latest message per customer with take and skip

Time:01-29

I have below customer and customer message model. I want to get top n customers with latest messages and have only the latest message per customer included.

I am using EfCore 7 on Postgres and my database has around a million customers and each customer might have a around 10 to 100 messages.

public class Customer 
{
    public long Id{ get; set;}
    public string LastName { get; set; }
    public string FirstName { get; set; }
    public ICollection<CustomerMessage>? CustomerMessages { get; set; }
}

public class CustomerMessage
{
    public long Id{ get; set;}
    public string Message { get; set; }
    public long CustomerId { get; set; }
    public Customer Customer { get; set; }
    public DateTime CreatedOnUtc{ get; set;}
}

Customer Message Table:

CustomerId Message Date
1 Test1 2022-01-01
1 Test2 2022-01-02
1 Test3 2022-01-01
2 Test4 2022-01-01
2 Test5 2022-01-04
2 Test6 2022-01-03
3 Test7 2022-01-03

Customer Table:

Id Name
1 John
2 Joe
3 Jim

Result with take=2, skip=0. result is based on latest messages received:

`[ { "Id":2, "Name":"Joe", "CustomerMessages":[{ "Message":"Test5"}]},

{ "Id:3, "Name":"Jim", "CustomerMessages":[{ "Message":"Test7"}]}]`

Please suggest thanks.

CodePudding user response:

Try the following query:

var n = 10;
var query = context.Customers
    .Include(c => c.CustomerMessages.OrderByDescending(m => m.CreatedOnUtc).Take(1))
    .Take(n)
    .ToList();

Or via custom projection, which is closer to your JSON

var n = 10;
var query = context.Customers
    .Take(n)
    .Select(c => new 
    {
        c.Id,
        Name = c.FirstName,
        CustomerMessages = c.CustomerMessages
            .OrderByDescending(m => m.CreatedOnUtc)
            .Take(1)
            .Select(m => new { m.Message })
            .ToList(),
    })
    .ToList();

UPDATE, based on updated requirements

var n = 10;

var joinQuery = 
    from c in context.Customers
    from m in c.CustomerMessages
        .OrderByDescending(m => m.CreatedOnUtc)
        .Take(1)
    orderby m.CreatedOnUtc descending
    select new 
    {
        Customer = c, 
        Message = new { m.Message }
    };

var query = joinQuery
    .Take(n)
    .Select(x => new 
    {
        x.Customer.Id,
        Name = x.Customer.FirstName,
        CustomerMessage = new { m.Message.Message },
    });
  • Related