Type safety and Query.EQ()

97 views
Skip to first unread message

mongotime

unread,
May 25, 2012, 7:09:06 AM5/25/12
to mongodb...@googlegroups.com
I started by writing code like so:

users.FindOneAs<User>(Query.EQ("username", Username)); 

but I was unhappy about having strings in the code for types which are known, so I moved to:

users.FindOneAs<User>(Query.EQ(Check(() => User.T.username ),  Username ));

by adding the following:

in User class:

public static readonly User T = null; 

locally:

        private static string Check<T>(Expression<Func<T>> expr)
        {
            var body = ((MemberExpression)expr.Body);
            return body.Member.Name;
        }

Now we have static checking, but a little more code. Is there a better way to do this using the driver without Linq?

Thanks



craiggwilson

unread,
May 25, 2012, 7:15:26 AM5/25/12
to mongodb...@googlegroups.com
Not currently.  Schedule for release 1.5 is support for typed query builders, so you could do this:  users.FindOneAs<User>(Query.Build<User>(u => u.T.username, "username"));

In the currently release, you can use linq for this.  Are you opposed to linq for some reason?  It isn't much different.  users.AsQueryable().Where(x => x.T.username == "username");

mongotime

unread,
May 25, 2012, 7:28:57 AM5/25/12
to mongodb...@googlegroups.com
Thanks Craig.

I haven't moved to Linq because I was not sure how/whether the mongodb specific update commands (inc, set, pushtoset, etc...) would translate to Linq.

I will bite the bullet eventually and read through the docs to see if everything I have written can be done in Linq.

craiggwilson

unread,
May 25, 2012, 7:56:43 AM5/25/12
to mongodb...@googlegroups.com
Remember that Linq is a query language, not an update language.  You can't use linq to to inc, set, pushtoset, etc... For now, you can use linq to do queries.  In 1.5, we will have typed update builders for update operations.

mongotime

unread,
May 25, 2012, 12:32:49 PM5/25/12
to mongodb...@googlegroups.com
Good point about linq only solving half the battle..... Will use my solution for now but will keep an eye out for 1.5 to see if it's less verbose. 

Thanks dude

Daniel Harman

unread,
May 28, 2012, 1:27:57 PM5/28/12
to mongodb...@googlegroups.com
That's great typed query builders are coming. I added them to the driver myself but never had time to do a pull request. 

Sent from my iPhone

craiggwilson

unread,
May 28, 2012, 6:46:24 PM5/28/12
to mongodb...@googlegroups.com
Yes, it's been a long time coming.  Actually, getting linq up and running enabled this to happen in a much better way.  I'd suggest you take a look at your implementation as there are a number of gotchas.  You might not use custom serializers, but our implementation will respect those registered.  For instance, if a class exists like this...

public class Person
{
  [BsonRepresentation(BsonType.ObjectId)]
  public string Id { get; set;}
}

...we'll take the string provided to us and send it mongodb as an objectid, exactly as it's stored.  Anyways, just a heads up if you are seeing anything weird through your typed builders.

Daniel Harman

unread,
May 28, 2012, 7:03:44 PM5/28/12
to mongodb...@googlegroups.com

I am sure your implementation is much better at dealing with edge cases. Mine was only a few hours work but not had any probs with it. I'll migrate to your version when it comes out. 

I didn't have to do anything that would have impacted on the serialisers though? It was just a case of modifying the builders to look at a lambda? Only thing I did was check which fields were mapped to id at n levels of nesting so that they would be mapped to 'id' in the query.

As an aide, I've been doing some work around object mapping of late. How are you getting/setting properties when serialising in the driver? Presumably a cache of getters/setters for a given type? I benchmarked a few ways of creating those delegates this morning and was surprised how much difference there was in perf between using Expression to build them vs Emit.

Dan 

craiggwilson

unread,
May 28, 2012, 8:38:29 PM5/28/12
to mongodb...@googlegroups.com
First access compiles a delegate to do it, so we get near compile time performance after the initial access.  For properties, we build an expression tree. For fields, we emit IL.  Did you find that emitting IL was faster than expressions?

Daniel Harman

unread,
May 29, 2012, 10:31:22 AM5/29/12
to mongodb...@googlegroups.com
Yes il generation about 3 times faster!


Sent from my iPhone

craiggwilson

unread,
Jun 1, 2012, 8:59:43 AM6/1/12
to mongodb...@googlegroups.com
Interesting.  The part we struggle with a little is that il emissions is incredibly complex and error prone, making it a less maintainable solution to the understandable Expression Tree.  Our tests are measuring the difference with millions of comparisons in order to get a significant deviation.  This means that it is probably better for us to use the maintainable version rather than il emission.  We'll talk internally about whether or not to switch over.  Thanks for your insight.

Daniel Harman

unread,
Jun 7, 2012, 11:48:02 AM6/7/12
to mongodb...@googlegroups.com
Yes for us the expression code does the get/set faster than our il alternative impl. Not had time to dig into why and its not immediately obvious by inspection. It's the il generation that is much faster which is a one time operation. We are using expression for properties ourselves as a result.

Just heard we need to support fields too, so may be browsing the driver soon for inspiration ;)

Dan

Sent from my iPad

craiggwilson

unread,
Jun 7, 2012, 4:03:22 PM6/7/12
to mongodb...@googlegroups.com
Fields are pretty easy using Expressions...  If you are on .NET 4.0, they are a piece of cake.  In 3.5, you still need to do il emit for setting fields.

Daniel Harman

unread,
Jun 7, 2012, 8:13:43 PM6/7/12
to mongodb...@googlegroups.com
Yes we did it - took 15 mins;) great to not have to support 3.5 :)

Sent from my iPad
Reply all
Reply to author
Forward
0 new messages