简体   繁体   中英

Simplify querying SQL in Entity Framework Core

I have the following code:

public async Task<IEnumerable<Submission>> SelectSubmissionsAsync(string submitterId, IEnumerable<Group> groups)
{
    var submissions = new List<Submission>();

    var apps = context.Apps
                      .Select(a => new
                                   {
                                       Id = a.Id,
                                       Member = a.MemberHistories.OrderByDescending(ash => ash.MemberChangeDate).FirstOrDefault().Member,
                                       Owner = a.OwnerHistories.OrderByDescending(oh => oh.OwnerChangeDate).FirstOrDefault().Owner
                                   }) 
                      .ToDictionary(x => x.Id, x => x.Member + x.Owner);

    var subs = context.Submissions.ToList();

    foreach (var sub in subs)
    {
        if (apps.ContainsKey((Guid)sub.AppId))
        {
            var value = apps[(Guid)sub.AppId];
            var check = value.Contains(submitterId, StringComparison.InvariantCultureIgnoreCase) || groups.Any(g => value.Contains(g.Id, StringComparison.InvariantCultureIgnoreCase));

            if (check) 
                submissions.Add(sub);
        }
    }
}


public class Submission
{
    public Guid Id { get; set; }       
    public Application App { get; set; }
    public Guid? AppId { get; set; }
}

public class App
{
    public Guid Id { get; set; }
    public string Identifier { get; set; }        
    public ICollection<MemberHistory> MemberHistories { get; set;}
    public ICollection<OwnerHistory> OwnerHistories { get; set;}
}

Is there a way to simplify this code (avoid for loop for example)?

Ideally you should be able to construct a single query looking something like this:

var appInfo = context.Apps
    .Select(a => new
        {
            Id = a.Id,
            Member = a.MemberHistories.OrderByDescending(ash => ash.MemberChangeDate).FirstOrDefault().Member,
            Owner = a.OwnerHistories.OrderByDescending(oh => oh.OwnerChangeDate).FirstOrDefault().Owner
        })
    .Where(appCriteria)
;
var submissions = context.Submissions
    .Where(s => appInfo.Any(app => s.AppId == app.Id))
    .ToList();

That will allow your app to build a single SQL command that filters the apps down to just the ones you want before bringing them back from the database.

Building checkCriteria will be complicated, because that's going to be based on the "OR"/Union of several criteria. You'll probably want to build a collection of those criteria, and then combine them using a strategy similar to what I've defined here . If you start with a collection of values including submitterId and groupIds , each criteria would be something like s => s.Member == val || s.Owner == val s => s.Member == val || s.Owner == val .

In order to create these expressions, you'll probably need to declare a class to represent the type that you're currently using an anonymous type for, so you have a name to associate with the generic arguments on your Expression types.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM