2

I have this ExecuteUpdate call below inside a for loop and I want to know if it's possible to eliminate the For loop and run ExecuteUpdate as one call?

foreach (var registrant in yogabandEvent.Registrants) 
{
    result = await _dbContext.Users
        .Where(p => p.Id == registrant.UserId)
    .ExecuteUpdateAsync(setters => setters
        .SetProperty(p => p.Attended, registrant.RegistrantType == RegistrantType.Student ? p => p.Attended + 1 : p => p.Attended)
        .SetProperty(p => p.Hosted, (registrant.RegistrantType == RegistrantType.Host || registrant.RegistrantType == RegistrantType.HostInstructor) ? p => p.Hosted + 1 : p => p.Hosted)
        .SetProperty(p => p.Instructed, registrant.RegistrantType == RegistrantType.Instructor ? p => p.Instructed + 1 : p => p.Instructed)
    );
}

2 Answers 2

0

ExecuteUpdate generates one update statement that is send to the database. Therefore, it's impossible to use complex local data, like yogabandEvent.Registrants, that are supposed to be read while the statement runs, and as such there's no way to eliminate the loop.

However, in your case the update can easily be restructured to create one update statement that does the job. Since you only update Users of which yogabandEvent.Registrants have type Student, you can first collect these Ids and use Contains in the update statement:

var studentIds = yogabandEvent.Registrants
    .Where(r => r.RegistrantType == RegistrantType.Student)
    .Select(r => r.UserId)
    .ToList();

result = await _dbContext.Users
               .Where(p => studentIds.Contains(p.Id))
               .ExecuteUpdateAsync(setters => setters
                   .SetProperty(p => p.Attended, p => p.Attended + 1));

Sign up to request clarification or add additional context in comments.

10 Comments

Hi thanks for the help. I actually have something a little more complex, but I left part of it out thinking it would be easier to get help. I'll edit my post above.
Then do it in three parts, for each SetProperty call.
How are the conditions checked?
I mean, collect the Ids three times for each of the registrant.RegistrantType == ... predicates and for each of these listst, do the above with the matching SetProperty call.
you mean run 3 different execute updates? Can this be done with 1 execute update?
|
0

I followed a users post who has since deleted it, but provided me with what I was looking for, so I will post my solution to my own question. You can see below that now I can provide a single call with no for loop that has conditions within each SetProperty that can be applied to a list of ID's, there by eliminating any for loop or executing multiple ExecuteUpdate calls.

 var studentIds = yogabandEvent.Registrants
    .Where(x => x.RegistrantType == RegistrantType.Student)
 .Select(x => x.UserId);

 var hostId = 1;          
 var instructorId = 2

 result = await _dbContext.Users
    .Where(p => yogaClass.Registrants.Select(x => x.UserId).Contains(p.Id))
 .ExecuteUpdateAsync(setters => setters
    .SetProperty(p => p.Attended, p => p.Attended + (studentIds.Contains(p.Id) ? 1 : 0))
    .SetProperty(p => p.Hosted, p => p.Hosted + (p.Id == hostId ? 1 : 0))
    .SetProperty(p => p.Instructed, p => p.Instructed + (p.Id == instructorId ? 1 : 0))
);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.