1
\$\begingroup\$

I have the following code where I need to execute 2 Linq-to-SQL statements. If I do not have the Any() in the if statement, then I receive error when the result is no data. However, I am not sure if my approach is efficient enough. Do you have any suggestions?

My goal is to achieve the following with single Linq statement. I need to get the Sum, and get 0 if there are no results.

 if (db.BadgeAssignments.Any(bba => bba.UserIdReceiver == newbadgeassignment.UserIdReceiver && bba.BadgeAssociated.CourseId == courseId))
 {
      currUserScore = db.BadgeAssignments
                        .Where(bba => bba.UserIdReceiver == newbadgeassignment.UserIdReceiver && bba.BadgeAssociated.CourseId == courseId)
                        .Sum(bba => bba.BadgeAssociated.Points);
 }
\$\endgroup\$
4
\$\begingroup\$

You have:

if (db.BadgeAssignments.Any(bba => bba.UserIdReceiver == newbadgeassignment.UserIdReceiver && bba.BadgeAssociated.CourseId == courseId))

And later:

.Where(bba => bba.UserIdReceiver == newbadgeassignment.UserIdReceiver && bba.BadgeAssociated.CourseId == courseId)

The two lambdas:

bba => bba.UserIdReceiver == newbadgeassignment.UserIdReceiver && bba.BadgeAssociated.CourseId == courseId
bba => bba.UserIdReceiver == newbadgeassignment.UserIdReceiver && bba.BadgeAssociated.CourseId == courseId

Identical. .Any is \$O(n)\$, meaning worst-case, it will have to iterate all elements of the source to find one that matches the predicate; Where is also \$O(n)\$, meaning it will traverse all elements of the source to find all that match the predicate.

currUserScore = db.BadgeAssignments
                  .Where(bba => bba.UserIdReceiver == newbadgeassignment.UserIdReceiver && bba.BadgeAssociated.CourseId == courseId)
                  .Sum(bba => bba.BadgeAssociated.Points);

This does it once, and will return 0 if no match is made while iterating BadgeAssignments... and that leaves you with a single linq statement =)

The predicate could be simplified further if you encapsulated it into a separate method:

currUserScore = db.BadgeAssignments
                  .Where(bba => IsMatch(bba, userId, courseId))
                  .Sum(bba => bba.BadgeAssociated.Points);

The IsMatch function (//todo: find a better name) is the lambda's body:

return bba.UserIdReceiver == userId
    && bba.BadgeAssociated.CourseId == courseId;
\$\endgroup\$
  • 1
    \$\begingroup\$ IsMatch won't work. EF will be unable to translate it into SQL and will crash. The OP put two mutually exclusive tags. With EF it will only work if you call AsEnumerable after the collection. \$\endgroup\$ – t3chb0t Nov 10 '16 at 18:02
  • \$\begingroup\$ @t3chb0t fair enough. that's what I get for coding in the answer box =) \$\endgroup\$ – Mathieu Guindon Nov 10 '16 at 18:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.