Lisum
Lisum

Reputation: 3

Entity Framework Core - Get multiple rows from one table as one DTO with multiple properties

Is it possible to select two rows into one anonymous object DTO with two properties? With a model like:

public class Document
{
    public int Id { get; set; }
    public string Text { get; set; }
    // Other properties
}

I am writing a method that finds the difference between two versions of a document:

public Task<string> CompareVersions(int initialId, int finalId)

So I need to retrieve the text of exactly two Documents by Id, and I need know which was which.

Currently I am constructing a Dictionary<int, string> by doing:

var dto = await _context.Documents
    .Where(doc => doc.Id == initialId
               || doc.Id == finalId)
    .ToDictionaryAsync(x => x.Id, x => x.Text);

and then calling dto[initialId] to get the text. However, this feels very cumbersome. Is there any way to take the two Ids and select them into one DTO in the form

{
    InitialText,
    FinalText
}

Upvotes: 0

Views: 883

Answers (2)

Caius Jard
Caius Jard

Reputation: 74605

Aggregate can do it too

var dto = (await _context.Documents
.Where(doc => doc.Id == initialId || doc.Id == finalId).ToListAsync())
.Aggregate(
  new { InitialText = "", FinalText = "" }, 
  (seed, doc) => { 
    if(doc.Id == initialId) 
      seed.InitialText = doc.Text; 
    else
      seed.FinalText = doc.Text;
  }
);

I'm not sure I like it any more than I do your dictionary approach, but with an actual dto at the end rather than the dictionary:

var d = await _context.Documents
.Where(doc => doc.Id == initialId || doc.Id == finalId)
.ToDictionaryAsync(x => x.Id, x => x.Text);
var dto = new { InitialText = d[initialId], FinalText = d[finalId] };

You could also perhaps just:

var dto = new { 
  InitialText = await context.Documents
.FindAsync(initialId),
  FinalText = await context.Documents
.FindAsync(finalId)
};

Upvotes: 0

Svyatoslav Danyliv
Svyatoslav Danyliv

Reputation: 27282

You have to use SelectMany

var query = 
   from initial in _context.Documents
   where initial.Id = initialId
   from final in _context.Documents
   where final.Id = finalId
   select new 
   {
      InitialText = initial.Text,
      FinalText = final.Text
   };

var result = await query.FirstOrDefaultAsync();

Upvotes: 1

Related Questions