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\$
0

1 Answer 1

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\$
2
  • 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, 2016 at 18:02
  • \$\begingroup\$ @t3chb0t fair enough. that's what I get for coding in the answer box =) \$\endgroup\$ Nov 10, 2016 at 18:05

Your Answer

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

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