patterncsharpMinor
Return most recent DateTime C# Entity Framework
Viewed 0 times
recentreturnentityframeworkmostdatetime
Problem
Job -> Many Quotes
Quote -> EmailLogList
EmailLogList -> Many EmailLogsI want to return a CreatedDate from an EmailLog which has been created most recently - using a Job.Guid.
Is this the best way possible?
public DateTime? GetMostRecentEmailLog(Guid jobGuid)
{
using (DbContext dbContext = new DbContext())
{
IEnumerable logLists = dbContext
.Jobs
.Include(j => j.Quotes)
.First(j => j.Guid == jobGuid)
.Quotes
.Where(q => q.EmailLogListGuid != null)
.Select(q => q.EmailLogListGuid);
return dbContext
.EmailLogs
.OrderByDescending(e => e.CreatedDate)
.Where(e => logLists.Contains(e.EmailLogListGuid))
.Select(e => e.CreatedDate)
.FirstOrDefault();
}
}Solution
This frequently used pattern...
... is hardly ever an economical way to do querying. It fetches a complete entity from the database of which subsequently all but one property is discarded. Or, when
In general a better way is...
... because this only gets the single property from the database.
Or, if
Applying this would turn the first statement into...
The second part is OK. Getting the most recent item from a collection always requires some ordering that defines "most recent".
Note that using the improved form, EF will translate this into one query, because
Or, if
1 Even though you cast the expression tree to
entities.First().Property... is hardly ever an economical way to do querying. It fetches a complete entity from the database of which subsequently all but one property is discarded. Or, when
Property is a lazy loaded collection, everything is discarded.In general a better way is...
entities.Where(e => e.Id == id).Select(e => e.Property).First()... because this only gets the single property from the database.
Or, if
Property is a collection,...entities.Where(e => e.Id == id)
.SelectMany(e => e.Property)
.Select(p => p.Property1)Applying this would turn the first statement into...
IEnumerable logLists = dbContext.Jobs
.Where(j => j.Guid == jobGuid)
.SelectMany(j => j.Quotes)
.Where(q => q.EmailLogListGuid != null)
.Select(q => q.EmailLogListGuid.Value);The second part is OK. Getting the most recent item from a collection always requires some ordering that defines "most recent".
Note that using the improved form, EF will translate this into one query, because
logList isn't materialized yet. It is an expression tree1 that can be merged with the second expression. If you want, you can create one statement in LINQ as well:return dbContext.Jobs
.Where(j => j.Guid == jobGuid)
.SelectMany(j => j.Quotes)
.SelectMany(q => dbContext.EmailLogs
.Where(e => q.EmailLogListGuid == e.EmailLogListGuid))
.OrderByDescending(e => e.CreatedDate)
.Select(e => e.CreatedDate)
.FirstOrDefault();Or, if
Quote has a navigation property EmailLogs (recommended):return dbContext.Jobs
.Where(j => j.Guid == jobGuid)
.SelectMany(j => j.Quotes)
.SelectMany(q => EmailLogs)
.OrderByDescending(e => e.CreatedDate)
.Select(e => e.CreatedDate)
.FirstOrDefault();1 Even though you cast the expression tree to
IEnumerable, it's still an IQueryable containing an expression.Code Snippets
entities.First().Propertyentities.Where(e => e.Id == id).Select(e => e.Property).First()entities.Where(e => e.Id == id)
.SelectMany(e => e.Property)
.Select(p => p.Property1)IEnumerable<Guid> logLists = dbContext.Jobs
.Where(j => j.Guid == jobGuid)
.SelectMany(j => j.Quotes)
.Where(q => q.EmailLogListGuid != null)
.Select(q => q.EmailLogListGuid.Value);return dbContext.Jobs
.Where(j => j.Guid == jobGuid)
.SelectMany(j => j.Quotes)
.SelectMany(q => dbContext.EmailLogs
.Where(e => q.EmailLogListGuid == e.EmailLogListGuid))
.OrderByDescending(e => e.CreatedDate)
.Select(e => e.CreatedDate)
.FirstOrDefault();Context
StackExchange Code Review Q#119830, answer score: 3
Revisions (0)
No revisions yet.