1

With a linq query I retrieve a list from the database. The list contains 2 items of a specific class containing the property RoleType. the type of RoleType is an int.

the first object has a property value 0. the second object has a property value 1.

I also got an enum:

enum RoleTypes
{
    Type1 = 1,
    Type2 = 0,
}

The weird order of indexing the enums is a given, I can't change that.

My business rules states that there has to be exactly one role with RoleType value Type2 and at least one role with RoleType value Type1. This is the code I use for that:

var ExactlyOneRoleType2 = roles.Count(role => role.RoleType == (int)RoleTypes.Type2) == 1;
var AtLeastOneRoleType1 = roles.Any(role => role.RoleType == (int)RoleTypes.Type1);

According to the list I mentioned earlier, both variables (ExactlyOneRoleType2 and AtLeastOneRoleType1) should be true. At least, I would expect that. Only if I debug through the code I found out that ExactlyOneRoleType2 is false. After some research I find out that

roles.Count(role => role.RoleType == (int)RoleTypes.Type2)

returns 2 instead of 1 which I find odd because there is only 1 role with RoleType Type2. Why does the count return 2? It also doesn't compute with the fact that the Any call actually returns true. How can list containing 2 items have both 2 items with RoleType Type2 and have at least one item with RoleType Type1?

Also when I change the count call to

roles.Count(role => role.RoleType == 0)

it still returns 2. Only when I change the Count call to this:

private static bool IsRoleTypeType2(Role role)
{
    return role.RoleType == (int)RoleTypes.Type2;
}

roles.Count(IsRoleTypeType2)

the count returns 1 as it should be.

What is happening here? Why does the count return 2 when I use a anonymous predicate? Did I misunderstood something about how the predicate works in case of count? Or is this is bug in Linq?

CodingWithSpike
  • 42,906
  • 18
  • 101
  • 138
Cornelis
  • 1,729
  • 5
  • 23
  • 39
  • 8
    It would *really* help if you'd provide a short but complete program demonstrating the problem. It's a lot easier to diagnose code that we can run... – Jon Skeet Sep 04 '14 at 12:13
  • Could you post all values found in roles? – Daniel Rose Sep 04 '14 at 12:15
  • @Daniel, you mean all the items in the roles list? there are only 2 items. That is part of the point here. – Cornelis Sep 04 '14 at 12:17
  • 1
    Are any of the RoleTypes not set? [the default value for an enum is whatever value has 0](http://stackoverflow.com/a/4967673/1324033) – Sayse Sep 04 '14 at 12:19
  • @Sayse all of them are set, it contains 5 items, running down from 1 to -3 (again, don't ask about the weird ordering of the enum index, it isn't my code I am only mainting and extending it) – Cornelis Sep 04 '14 at 12:23
  • Cornelis - Just for a simple check do `roles.Select(x => (int)x.RoleType)` – Sayse Sep 04 '14 at 12:24
  • Is `roles` an in-memory list/enumerable, or is it an entity framework `iQueryable`? You mentioned pulling the data from a DB. The Linq provider would be different between the two, so would help in diagnosing the issue. – CodingWithSpike Sep 04 '14 at 12:28
  • @CodingWithSpike roles is an IQueryable (from LLBLGen, also an ORM framework). – Cornelis Sep 04 '14 at 12:40
  • @Sayse when I do that, the count returns 3. I also tried to convert the IQueryable to a List and then the count returns 1 like it should be. Is the IQueryable doing something I weird? When I mouse over my IQueryable roles and I unfold it, I see 2 items. But when I do a .Count on my IQueryable roles in my watches, it says it has 3 items. I am a bit confused now here :) – Cornelis Sep 04 '14 at 12:41
  • Have you tried run db profiler to check what the query is generated on database side? – Stephen Zeng Sep 04 '14 at 12:47
  • 1
    Yeah my guess is that LLBLGen provides an `IQueryProvider`implementation that parses the LINQ query into a SQL statement, and is probably doing it wrong. If you can enable logging on your DB and capture the queries that are being executed, it would be interesting to see what it generated. (I also added the LLBLGen tag to your post) – CodingWithSpike Sep 04 '14 at 12:51
  • As a workaround, try: `roles.Where(role => role.RoleType == (int)RoleTypes.Type2).ToList().Count() == 1;` The `where` should limit your SQL query through LLBLGen, then the `tolist` should "read" your records into an in-memory list, and the final `count` should get the number of items in the list using Linq2Objects, not LLBLGen's implementation. – CodingWithSpike Sep 04 '14 at 12:57
  • I don't think it would be possible to debug without more code. Also, I think part of the problem is casting the roletype to an int and comparing that. – DidIReallyWriteThat Sep 04 '14 at 12:58
  • @CalvinSmith - He mentioned at the end of his question that he also tried `roles.Count(role => role.RoleType == 0)` directly without the use of the enum, so the cast is not the issue. – CodingWithSpike Sep 04 '14 at 13:00
  • @Calvin I also tried to do it without any casting and just put the 0 in the equation instead. I managed to capture the query that LLBLGEN generated and the query returns 2 records. – Cornelis Sep 04 '14 at 13:02

0 Answers0