Greater than on enum value not working as expected (Linq)

141 views
Skip to first unread message

Stijn Volders (ONE75)

unread,
Apr 25, 2012, 5:17:58 PM4/25/12
to rav...@googlegroups.com
I'm trying to retrieve documents based on this query:

var importantBacklogItems = _session.Query<BacklogItem>().Where(bli => bli.BusinessValue >= BusinessValue.L);

the BusinessValue enum:

    public enum BusinessValue
    {
        XL = 5,
        L = 4,
        M = 3,
        S = 2,
        XS = 1
    }

This should yield 6 documents out of 8, but I'm getting all 8 as a result.

If run the same query on a collection in memory, I get the correct results as expected (6 documents):

So, this fails:
        [Test]
        public void All_backlogItems_with_a_BusinessValue_equal_or_higher_than_Large()
        {
            var importantBacklogItems = _session.Query<BacklogItem>().Where(bli => bli.BusinessValue >= BusinessValue.L);
            Assert.AreEqual(6, importantBacklogItems.Count());
        }

This works:
        [Test]
        public void All_backlogItems_with_a_BusinessValue_equal_or_higher_than_Large_On_a_collection_in_memory()
        {
            var allbacklogitems = _session.Query<BacklogItem>().ToList();
            var importantBacklogItems = allbacklogitems.Where(bli => bli.BusinessValue >= BusinessValue.L);
            Assert.AreEqual(6, importantBacklogItems.Count());
        }

So, I partially know why this is happening: RavenDB is not (and cannot) use the int values of my enum (they are not stored in the document). Question is: (how) can I make sure RavenDB is acting the same as the default Linq provider.

btw, is there a way to see the Lucene queries that are send to RavenDB?

Matt Warren

unread,
Apr 25, 2012, 5:43:04 PM4/25/12
to rav...@googlegroups.com
> btw, is there a way to see the Lucene queries that are send to RavenDB?

This will give you the lucene query:  
    var importantBacklogItems = _session.Query<BacklogItem>()
                                        .Where(bli => bli.BusinessValue >= BusinessValue.L)
                                        .ToString()

Or use fiddler and watch the network traffic (if running Client/Server)

Beyers

unread,
Apr 25, 2012, 6:47:19 PM4/25/12
to rav...@googlegroups.com
So, I partially know why this is happening: RavenDB is not (and cannot) use the int values of my enum (they are not stored in the document). Question is: (how) can I make sure RavenDB is acting the same as the default Linq provider.


You can set Raven to store enums as integers and then range queries as per your examples will work as expected.

RavenDocumentStore = new DocumentStore { ConnectionStringName = "RavenDB" };
RavenDocumentStore.Conventions.SaveEnumsAsIntegers = true;

The downside is obviously that you loose readability when viewing documents in Raven Studio as you will see integers instead of the enum text. Also changing your enum definition could be troublesome since Raven will just map the integer value to enum at any given point.

Matt Warren

unread,
Apr 26, 2012, 4:04:23 AM4/26/12
to rav...@googlegroups.com
What about treating Enum like numbers are treated at the moment, i.e given the enum above

public enum BusinessValue
    {
        XL = 5,
        L = 4,
        M = 3,
        S = 2,
        XS = 1
    }

Store it field called "BusinessValue" as:
  • BusinessValue - "XL" or "L" etc
  • BusinessValue_Range - 0x0005, 0x0004 (the hex representation for sorting)
Then you have the best of both worlds, you can load up the actual value as text and sort on it as a number? 

Oren Eini (Ayende Rahien)

unread,
Apr 27, 2012, 7:15:15 PM4/27/12
to rav...@googlegroups.com
How do I know that on the server? 
Or do you means that this should be done on the client during deserialization?

Matt Warren

unread,
Apr 29, 2012, 10:32:06 AM4/29/12
to rav...@googlegroups.com
On Saturday, 28 April 2012 00:15:15 UTC+1, Oren Eini wrote:
How do I know that on the server? 

Oh yeah, I forgot all the existing "_Range" stuff is done on the server side and that an enum would already by a string or int by the time it gets there.
 
Or do you means that this should be done on the client during deserialization?

What about adding some sort of suffix in the Json, during deserialisation (like you suggest)

So given a POCO like this:

public class
{
    public string Id { get; set; }
    public BusinessValue Value { get; set; }
}

This Json would get generated
{
    "Value" : "XL",
    "Value_IsEnum" : 5
    .....
}

Then the server can handle this and store "Value_IsEnum" in Lucene as 0x00005. Then the LINQ Api can do the type of conversions it already does for numbers.

Or is it a bit of a hack changing the serialized Json like this, just to enable the client and the server to preserve the enum info.
 

Oren Eini (Ayende Rahien)

unread,
Apr 29, 2012, 10:41:11 AM4/29/12
to rav...@googlegroups.com
Matt,
That is something that the user can add on their own, I don't see this adding value to the server.
And honestly, it is a pretty rare feature to want.
Reply all
Reply to author
Forward
0 new messages