$30 off During Our Annual Pro Sale. View Details »

New LINQ support in C#/.NET driver Robert Stam, 10gen

mongodb
August 16, 2012
40k

New LINQ support in C#/.NET driver Robert Stam, 10gen

Using LINQ queries with the C#/.Net driver

The C#/.NET driver recently introduced support for LINQ queries. Learn how to query MongoDB using LINQ, with lots of examples and an explanation of what kinds of LINQ queries are supported. Learn how support for LINQ is implemented, and how LINQ queries are translated to equivalent queries in the native MongoDB query language.

mongodb

August 16, 2012
Tweet

Transcript

  1. 1
    August  15,  2012
    Open  source,  high  performance  database
    LINQ in the C#/.NET Driver
    Robert Stam
    Software Engineer, 10gen
    Wednesday, August 15, 12

    View Slide

  2. • Added in the 1.4 release
    • Enhanced in 1.4.1, 1.4.2 and 1.5
    • Think of LINQ as just another way to write
    your queries
    • A higher level of abstraction: write your
    queries in C#
    • A data-source neutral query language
    2
    LINQ support in the C#/.NET driver
    Wednesday, August 15, 12

    View Slide

  3. 3
    • Typical  na=ve  query
    > db.employees.find({
    Name : /^John/
    Salary : { $gte : 100000 }
    })
    {
    Name : "John Doe",
    Salary : 120000,
    ....
    }
    ...
    >
    Native queries (in the mongo shell)
    Wednesday, August 15, 12

    View Slide

  4. 4
    • Typical  na=ve  query  in  C#
    var collection = database.GetCollection("employees");
    var query = Query.And(
    Query.Matches("Name", "/^John/"),
    Query.GTE("Salary", 100000)
    );
    foreach (var employee in collection.Find(query)) {
    // process employee
    }
    Native queries (in C#)
    Wednesday, August 15, 12

    View Slide

  5. 5
    • LINQ  is  supported  for  queries  only  (although  
    Query.Where  supports  wri=ng  predicates  in  C#  
    that  can  be  used  with  Update)
    • You  opt-­‐in  to  LINQ  using  AsQueryable()
    Using LINQ for queries
    Wednesday, August 15, 12

    View Slide

  6. 6
    • Typical  query  using  LINQ
    var collection = database.GetCollection("employees");
    var query =
    from e in collection.AsQueryable()
    where e.Name.StartsWith("John") && e.Salary >= 100000
    select e;
    foreach (var employee in query) {
    // process employee
    }
    Using LINQ for queries
    Wednesday, August 15, 12

    View Slide

  7. 7
    • C#  compiler  creates  an  Expression  tree
    • C#/.NET  driver  translates  the  Expression  tree  to  an  
    equivalent  MongoDB  query  at  run  =me
    • Requirements
    – For  each  C#  property  referenced  in  the  LINQ  query  the  
    driver  has  to  be  able  to  figure  out  the  matching  element  
    name  in  the  BSON  document  (using  doZed  names  for  
    nested  elements)
    – For  each  test  using  those  C#  proper=es  the  driver  has  to  be  
    be  able  to  translate  the  test  into  an  equivalent  MongoDB  
    query  operator
    What's really happening when you use LINQ?
    Wednesday, August 15, 12

    View Slide

  8. 8
    • The  primary  goal  is:  we  will  only  support  LINQ  queries  
    that  have  a  reasonable  transla=on  to  an  equivalent  
    MongoDB  query
    • The  reason:  we  want  to  ensure  predictable  
    performance  from  LINQ  queries  (no  black  magic,  no  
    surprises)
    • So,  you  will  not  find:
    – Any  hidden  map/reduce  or  Javascript  tricks
    – Any  hidden  client  side  processing
    • Online  LINQ  tutorial  at:  hZp://www.mongodb.org/display/DOCS/
    CSharp+Driver+LINQ+Tutorial
    Design goals of the LINQ support
    Wednesday, August 15, 12

    View Slide

  9. 9
    var query =
    from e in collection.AsQueryable()
    where e.EmployeeStatus == Status.Active
    select e;
    // translates to (assuming enum value for Active is 1):
    { EmployeeStatus : 1 }
    var query =
    from e in collection.AsQueryable()
    where e.EmployeeStatus != Status.Active
    select e;
    // translates to:
    { EmployeeStatus : { $ne : 1 } }
    Sample LINQ queries (== and !=)
    Wednesday, August 15, 12

    View Slide

  10. 10
    var query =
    from e in collection.AsQueryable()
    where
    e.EmployeeStatus == Status.Active &&
    e.Salary > 100000
    select e;
    // translates to:
    { EmployeeStatus : 1, Salary : { $gt : 100000 } }
    Sample LINQ queries (&&)
    Wednesday, August 15, 12

    View Slide

  11. 11
    var query =
    from e in collection.AsQueryable()
    where
    e.EmployeeStatus == Status.Active ||
    e.Salary > 100000
    select e;
    // translates to:
    { $or : [
    { EmployeeStatus : 1 },
    { Salary : { $gt : 100000 } }
    ]}
    Sample LINQ queries (||)
    Wednesday, August 15, 12

    View Slide

  12. 12
    var query =
    from e in collection.AsQueryable()
    where e.Name.Contains("oh")
    select e;
    // translates to:
    { nm: /oh/s }
    var query =
    from e in collection.AsQueryable()
    where e.Name.StartsWith("John")
    select e;
    // translates to:
    { nm: /^John/s }
    Sample LINQ queries (string Contains, StartsWith)
    Wednesday, August 15, 12

    View Slide

  13. 13
    var query =
    from e in collection.AsQueryable()
    where e.Name.Length == 4
    select e;
    // translates to:
    { nm: /^.{4}$/s }
    var query =
    from e in collection.AsQueryable()
    where string.IsNullOrEmpty(e.Name)
    select e;
    // translates to:
    { $or : [ { nm: { $type : 10 } }, { nm: "" } ] }
    Sample LINQ queries (string Length, IsNullOrEmpty)
    Wednesday, August 15, 12

    View Slide

  14. 14
    var query =
    from e in collection.AsQueryable()
    where e.Name.ToLower() == "john macadam"
    select e;
    // translates to:
    { nm: /^john macadam$/is }
    Sample LINQ queries (string ToLower)
    Wednesday, August 15, 12

    View Slide

  15. 15
    var query =
    from e in collection.AsQueryable()
    where e.Skills[0] == "Java"
    select e;
    // translates to:
    { "Skills.0" : "Java" }
    var query =
    from e in collection.AsQueryable()
    where e.Skills.Length == 3
    select e;
    // translates to:
    { Skills : { $size : 3 } }
    Sample LINQ queries (array element, Length)
    Wednesday, August 15, 12

    View Slide

  16. 16
    var query =
    from e in collection.AsQueryable()
    where e.Address.City == "Hoboken"
    select e;
    // translates to:
    { "Address.City" : "Hoboken" }
    Sample LINQ queries (dotted names)
    Wednesday, August 15, 12

    View Slide

  17. 17
    var states = new [] { "NJ", "NY", "PA" };
    var query =
    from e in collection.AsQueryable()
    where states.Contains(e.Address.State)
    select e;
    // translates to:
    { "Address.State" : { $in : [ "NJ", "NY", "PA" ] } }
    // alternative syntax using C#/.NET driver "In" method
    var query =
    from e in collection.AsQueryable()
    where e.Address.State.In(states)
    select e;
    Sample LINQ queries ($in)
    Wednesday, August 15, 12

    View Slide

  18. 18
    var desiredSkills = new [] { "Java", "C#" };
    var query =
    from e in collection.AsQueryable()
    where e.Skills.ContainsAny(desiredSkills)
    select e;
    // translates to:
    { "Skills" : { $in : [ "Java", "C#" ] } }
    var query =
    from e in collection.AsQueryable()
    where e.Skills.ContainsAll(desiredSkills)
    select e;
    // translates to:
    { "Skills" : { $all : [ "Java", "C#" ] } }
    note: ContainsAny and ContainsAll are defined by the C#/.NET
    driver and are not part of standard LINQ
    Sample LINQ queries ($in/$all with arrays)
    Wednesday, August 15, 12

    View Slide

  19. 19
    var query =
    from e in collection.AsQueryable()
    where
    e.Addresses.Any(a =>
    a.City == "Hoboken" &&
    a.State == "NJ")
    select e;
    // translates to:
    { "Addresses" : { $elemMatch :
    { City : "Hoboken", State : "NJ" } } }
    Sample LINQ queries ($elemMatch)
    Wednesday, August 15, 12

    View Slide

  20. 20
    • You  can  "Inject"  na=ve  MongoDB  queries  into  a  LINQ  
    query  if  you  need  to  include  a  test  that  LINQ  doesn't  
    support,  without  giving  up  LINQ  en=rely
    var query =
    from e in collection.AsQueryable()
    where
    e.Salary > 50000 &&
    Query.NotExists("EmployeeStatus").Inject()
    select e;
    // translates to:
    {
    Salary : { $gt : 50000 },
    EmployeeStatus : { $exists : false }
    }
    Mixing LINQ with MongoDB queries
    Wednesday, August 15, 12

    View Slide

  21. 21
     
    Open  source,  high  performance  database
    Q&A
    Robert Stam
    Software Engineer, 10gen
    Wednesday, August 15, 12

    View Slide