.NET Database Technologies
Entity Framework: Queries and Transactions
ORMs and query languages
l With an ORM, queries must define data to be returned and criteria in terms of domain model objects and their properties
l Framework translates object query to query understood by underlying data store (SQL)
l Many query languages have been created for specific ORMs on .NET and other platforms
l e.g. HQL, JPQL, EJB QL, Entity SQL l Generally use “magic strings”
En$ty Framework: queries and transac$ons 2
ORM query language examples
l HQL (Hibernate, NHibernate)
l Entity SQL
En$ty Framework: queries and transac$ons 3
using (var tx = session.BeginTransaction()) { int count = (int) session .CreateQuery("select count(*) from Trip") .UniqueResult(); tx.Commit(); }
Language integrated queries l LINQ offers .NET applications the capability to
defined type-safe queries[1] l Compile-time checking and Intellisense
l Not specific to ORMs, supported by providers for many data sources
l Preferred way of defining queries in EF, supported by NHibernate and other .NET ORMs
l Other type-safe query languages have also been created/proposed, e.g. Native Queries supported in db4o object database[2]
En$ty Framework: queries and transac$ons 4
LINQ
l General-purpose query facilities for .NET that apply to all sources of information, not just relational or XML data
l Queries expressed using query syntax or standard query operators
l EF supports LINQ to Entities En$ty Framework: queries and transac$ons
5
LINQ to Entities
En$ty Framework: queries and transac$ons 6
type is DbSet, implements IQueryable
extension methods, act on IQueryable and return IQueryable, methods defined in System.Linq.Queryable class
derived from DbContext
deferred execution - query not sent to database until results are “touched”, e.g. by enumerating with foreach or returning results as List or array
ToList forces execution
Compare this to LINQ to Objects queries, which operate on IEnumerable, extension methods in System.Linq.Enumerable class
Lambda functions/expressions
l Lambda expressions provide a compact syntax for authoring query operators
l Lambda can represent a function or an expression
l f is a reference to an executable delegate l e is a reference to an expression tree which
is not directly executable En$ty Framework: queries and transac$ons
7
Expression trees
l Expression tree is a data structure l Can be traversed and modified at runtime l Expression class or subclass properties (e.g.
BinaryExpression, LambdaExpression): l Body l Parameters l Left/Right l NodeType l Type
l Compile method converts to callable code En$ty Framework: queries and transac$ons
8
Expression trees
En$ty Framework: queries and transac$ons 9
Expression definition
LambdaExpression
LambdaExpression.Body is instance of BinaryExpression
Entity Framework expressions
l LINQ to Entities expects Expression rather than Func for query operator, e.g. l Expression<Func<DomainType, bool>> is required
for filtering with Where l Expression here is a predicate object that
represents a query criterion l Expression<Func<DomainType, ResultType>> is
required for Select
En$ty Framework: queries and transac$ons 10
Entity Framework expressions
l IQueryable has property of type Expression l Holds the expression tree for that instance l Tree is built from all the expressions which
combine to define that query, including those used in Where, OrderBy, Select, etc.
l Easier to translate a data structure into SQL than to translate executable code into SQL
En$ty Framework: queries and transac$ons 11
Combining expressions
l Can combine criteria in a query with chained calls to Where (not ideal)
l Equivalent to:
En$ty Framework: queries and transac$ons 12
Query object pattern
l An object that represents a database query –Fowler
l A LINQ expression can be thought of as an implementation of the pattern
l Quite closely follows Fowler’s description l Arguably no need to implement your own…
En$ty Framework: queries and transac$ons 13
Query objects
l However, it can be useful to design your own query objects at a higher level of abstraction
l Can improve separation of concerns, e.g. remove query logic from repositories
l Can create testable query logic – useful if query is complex
l One approach is to encapsulate parameter(s) as properties of QO class and provide method to return an expression[3]
En$ty Framework: queries and transac$ons 14
Query object example
l Query object class
l Creating and using a query object
En$ty Framework: queries and transac$ons 15
Composing expressions
l Query Object pattern suggests the ability to build a single object composed of criteria
l Arguably a LINQ query provides this, but we can also compose criteria explicitly before using in LINQ query
l Expression tree can be manipulated at runtime, but this can be tricky
l PredicateBuilder[4] makes this easier to do
En$ty Framework: queries and transac$ons 16
Using PredicateBuilder
l Need to download and have reference to LinqKit.dll
En$ty Framework: queries and transac$ons 17
AsExpandable method provided by LinqKit, required for EF queries
Composed query class
l Rather than composing in client code we can build specific query class from simpler queries
En$ty Framework: queries and transac$ons 18
Composed query class
En$ty Framework: queries and transac$ons 19
Query object design
l No single definitive way to design query objects
l Many examples to be found l For example, some authors define queries as an
additional set of extension methods on IQueryable l Some refer to “Specification” pattern
l Design of queries and the way they are used, e.g. within or instead of repositories, is an important part of application architecture
En$ty Framework: queries and transac$ons 20
LINQ queries compared to SQL l SQL operates on a relation and returns a
relation l Need to explicitly JOIN associated entities l LINQ can return complex object graph
l Can return domain objects l Can project to new anonymous object built from
properties/objects returned by query l LINQ can navigate relationships between
associated entities l Don’t always need to use Join
En$ty Framework: queries and transac$ons 21
Fetch strategy
l Unless you are using lazy loading you need to consider fetch strategy carefully
l Make sure any associated objects which client code needs are materialised
l If not, can get null reference exceptions when accessing object members
l Careful use of Include is required
En$ty Framework: queries and transac$ons 22
Fetch strategy example
l Use LinqPad to visualise results l No eager loading, Department only
En$ty Framework: queries and transac$ons 23
Fetch strategy examples
l Include Employees collection
En$ty Framework: queries and transac$ons 24
Fetch strategy examples
l Include Address property of each Employee
En$ty Framework: queries and transac$ons 25
Division of responsibility
l Query logic and fetch strategy are distinct responsibilities
l Need to design an architecture which places these responsibilities in appropriate classes
l Many different approaches possible l Look at examples later when we look more
closely at repositories l Summarise one possible approach briefly
here En$ty Framework: queries and transac$ons
26
Division of responsibility
l Use query objects, or simply Expressions, to encapsulate query criteria
l Expose domain objects to client through repository as IQueryable
l Repository uses query objects, possibly passed from client as parameters
l Client (e.g. MVC controller or service layer method) applies fetch strategy to result – client knows what objects are required for the operation it needs to perform
En$ty Framework: queries and transac$ons 27
Finding a single object with Find
l Find is a method of DbSet by PK l Return type is Object, can’t access
associated objects unless already loaded l A round-trip to the database will only be
made if the entity with the given key is not found in the context
l Find will return entities that are in the Added state, i.e. Find will return entities that have been added to the context but have not yet been saved to the database
En$ty Framework: queries and transac$ons 28
Find examples
En$ty Framework: queries and transac$ons 29
Native SQL queries
l Most ORMs allow SQL or calls to stored procedures to be sent to database – “native” (to database) query
l EF allows SQL queries to return entities or primitive types
l Queries as magic strings l Can call stored procedures and pass
parameters to them
En$ty Framework: queries and transac$ons 30
SQL query examples
En$ty Framework: queries and transac$ons 31
Transactions
l DbContext to some extent defines transactions l Changes are not sent to database until committed
with SaveChanges l May want to encapsulate operations in true
transactions l Use TransactionScope in .NET l Needs to be supported by database provider l Local or distributed transactions
l Transaction can include multiple contexts En$ty Framework: queries and transac$ons
32
Transactions example
En$ty Framework: queries and transac$ons 33
• Save changes in two contexts • Object added to second context is
invalid, will throw exception on SaveChanges
• Changes already saved within transaction through first context will also roll back
ObjectContext
l DbContext provides a useful set of functionality, but some capabilities of ObjectContext are not provided
l Need to drop down to underlying ObjectContext in some (rare) circumstances
l (can do this with DbContext – better example is to generate EDMX…..)
En$ty Framework: queries and transac$ons 34
References
1. http://msdn.microsoft.com/en-us/library/bb308959.aspx
2. http://www.drdobbs.com/database/native-queries-for-persistent-objects/184406432
3. http://lostechies.com/chadmyers/2008/08/02/query-objects-with-the-repository-pattern/
4. http://www.albahari.com/nutshell/predicatebuilder.aspx
En$ty Framework: queries and transac$ons 35