Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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
  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
  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
  4. 4 • Typical  na=ve  query  in  C# var collection =

    database.GetCollection<Employee>("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
  5. 5 • LINQ  is  supported  for  queries  only  (although  

    Query<T>.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
  6. 6 • Typical  query  using  LINQ var collection = database.GetCollection<Employee>("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
  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
  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
  9. 9 var query = from e in collection.AsQueryable<Employee>() 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<Employee>() where e.EmployeeStatus != Status.Active select e; // translates to: { EmployeeStatus : { $ne : 1 } } Sample LINQ queries (== and !=) Wednesday, August 15, 12
  10. 10 var query = from e in collection.AsQueryable<Employee>() where e.EmployeeStatus

    == Status.Active && e.Salary > 100000 select e; // translates to: { EmployeeStatus : 1, Salary : { $gt : 100000 } } Sample LINQ queries (&&) Wednesday, August 15, 12
  11. 11 var query = from e in collection.AsQueryable<Employee>() 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
  12. 12 var query = from e in collection.AsQueryable<Employee>() where e.Name.Contains("oh")

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

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

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

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

    == "Hoboken" select e; // translates to: { "Address.City" : "Hoboken" } Sample LINQ queries (dotted names) Wednesday, August 15, 12
  17. 17 var states = new [] { "NJ", "NY", "PA"

    }; var query = from e in collection.AsQueryable<Employee>() 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<Employee>() where e.Address.State.In(states) select e; Sample LINQ queries ($in) Wednesday, August 15, 12
  18. 18 var desiredSkills = new [] { "Java", "C#" };

    var query = from e in collection.AsQueryable<Employee>() where e.Skills.ContainsAny(desiredSkills) select e; // translates to: { "Skills" : { $in : [ "Java", "C#" ] } } var query = from e in collection.AsQueryable<Employee>() 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
  19. 19 var query = from e in collection.AsQueryable<Employee>() 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
  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
  21. 21   Open  source,  high  performance  database Q&A Robert Stam

    Software Engineer, 10gen Wednesday, August 15, 12