diff --git a/doc/reference/master.xml b/doc/reference/master.xml
index 335216513d4..b28a8eb5148 100644
--- a/doc/reference/master.xml
+++ b/doc/reference/master.xml
@@ -17,6 +17,7 @@
+
@@ -67,6 +68,7 @@
&query-hql;
&query-criteria;
&query-queryover;
+ &query-linq;
&query-sql;
&filters;
diff --git a/doc/reference/modules/query_linq.xml b/doc/reference/modules/query_linq.xml
new file mode 100644
index 00000000000..32e0e041aa1
--- /dev/null
+++ b/doc/reference/modules/query_linq.xml
@@ -0,0 +1,660 @@
+
+ Linq Queries
+
+
+ NHibernate 3.0 introduces the Linq to NHibernate provider, which allows the use of the Linq API
+ for querying with NHibernate.
+
+
+ The Linq provider works as an extension of the ISession. It is defined in the
+ NHibernate.Linq namespace, so this namespace has to be imported for using the
+ Linq provider. Of course, the LINQ namespace is still needed too.
+
+
+
+ Note: NHibernate has another querying API which uses lambda, QueryOver.
+ It should not be confused with a LINQ provider.
+
+
+
+ Structure of a Query
+
+
+ Queries are created from an ISession using the syntax:
+
+ cats =
+ session.Query()
+ .Where(c => c.Color == "white")
+ .ToList();]]>
+
+ The Query<TEntity> function yields an IQueryable<TEntity>,
+ with which Linq extension methods or Linq syntax can be used. When executed, the IQueryable<TEntity>
+ will be translated to a SQL query on the database.
+
+
+
+
+ It is possible to query a specific sub-class while still using a queryable of the base class.
+
+ cats =
+ session.Query("Eg.DomesticCat, Eg")
+ .Where(c => c.Name == "Max")
+ .ToList();]]>
+
+
+ A client timeout for the query can be defined.
+
+ cats =
+ session.Query()
+ .Where(c => c.Color == "black")
+ // Allows 10 seconds only.
+ .TimeOut(10)
+ .ToList();]]>
+
+
+
+ Parameter types
+
+
+ Query parameters get extracted from the Linq expression. Their types are selected according to
+ NHibernate types default for .Net types.
+
+
+ The MappedAs extension method allows to override the default type.
+
+ cats =
+ session.Query()
+ .Where(c => c.BirthDate == DateTime.Today.MappedAs(NHibernateUtil.Date))
+ .ToList();]]>
+
+
+
+ Supported methods and members
+
+
+ Many methods and members of common .Net types are supported by the Linq to NHibernate provider.
+ They will be translated to the appropriate SQL, provided they are called on an entity property
+ (or expression deriving from) or at least one of their arguments references an entity property.
+ (Otherwise, their return values will be evaluated with .Net runtime before query execution.)
+
+
+
+ Common methods
+
+
+ The .Net 4 CompareTo method of strings and numerical types is translated to
+ a case statement yielding -1|0|1 according to the result
+ of the comparison.
+
+
+
+
+ Many type conversions are available. For all of them, .Net overloads with more than one argument
+ are not supported.
+
+
+ Numerical types can be converted to other numerical types or parsed from strings, using
+ following methods:
+
+
+
+
+ Convert.ToDecimal
+
+
+
+
+ Convert.ToDouble
+
+
+
+
+ Convert.ToInt32
+
+
+
+
+ Decimal.Parse
+
+
+
+
+ Double.Parse
+
+
+
+
+ Int32.Parse
+
+
+
+
+ Strings can be converted to Boolean and DateTime with
+ Convert.ToBoolean or Boolean.Parse and
+ Convert.ToDateTime or DateTime.Parse respectively.
+
+
+ On all types supporting string conversion, ToString method can be called.
+
+ catBirthDates =
+ session.Query()
+ .Select(c => c.BirthDate.ToString())
+ .ToList();]]>
+
+
+
+ Equals methods taking a single argument with the same type can be used. Of
+ course, == is supported too.
+
+
+
+
+ DateTime and DateTimeOffset
+
+
+ Date and time parts properties can be called on DateTime and DateTimeOffset.
+ Those properties are:
+
+
+
+
+ Date
+
+
+
+
+ Day
+
+
+
+
+ Hour
+
+
+
+
+ Minute
+
+
+
+
+ Month
+
+
+
+
+ Second
+
+
+
+
+ Year
+
+
+
+
+
+
+ ICollection, non generic and generic
+
+
+ Collections Contains methods are supported.
+
+ catsWithWrongKitten =
+ session.Query()
+ .Where(c => c.Kittens.Contains(c))
+ .ToList();]]>
+
+
+
+ IDictionary, non generic and generic
+
+
+ Dictionaries Item getter are supported. This enables referencing a dictionary
+ item value in a where condition, as it can be done with
+ HQL expressions.
+
+
+ Non generic dictionary method Contains and generic dictionary method
+ ContainsKey are translated to corresponding indices
+ HQL expressions. Supposing Acts
+ in following HQL example is generic,
+
+
+
+ it could be written with Linq:
+
+ shows =
+ session.Query()
+ .Where(s => s.Acts.ContainsKey("fizard"))
+ .ToList();]]>
+
+
+
+ Mathematical functions
+
+
+ The following list of mathematical functions from System.Math is handled:
+
+
+
+
+
+ Trigonometric functions: Acos, Asin, Atan,
+ Atan2, Cos, Cosh, Sin,
+ Sinh, Tan, Tanh
+
+
+
+
+ Abs (all overloads)
+
+
+
+
+ Ceiling (both overloads)
+
+
+
+
+ Floor (both overloads)
+
+
+
+
+ Pow
+
+
+
+
+ Round (only overloads without a mode argument)
+
+
+
+
+ Sign (all overloads)
+
+
+
+
+ Sqrt
+
+
+
+
+ Truncate (both overloads)
+
+
+
+
+
+
+ Nullables
+
+
+ On Nullable<> types, GetValueOrDefault methods, with or
+ without a provided default value, are supported.
+
+
+
+
+ Strings
+
+ Following properties and methods are supported on strings:
+
+
+
+
+ Contains
+
+
+
+
+ EndsWith (without additional parameters)
+
+
+
+
+ IndexOf (only overloads taking a character or a string, and optionally a start index)
+
+
+
+
+ Length
+
+
+
+
+ Replace (both overloads)
+
+
+
+
+ StartsWith (without additional parameters)
+
+
+
+
+ Substring (both overloads)
+
+
+
+
+ ToLower (without additional parameters) and ToLowerInvariant,
+ both translated to the same database lower function.
+
+
+
+
+ ToUpper (without additional parameters) and ToUpperInvariant,
+ both translated to the same database upper function.
+
+
+
+
+ Trim (both overloads)
+
+
+
+
+ TrimEnd
+
+
+
+
+ TrimStart
+
+
+
+
+
+
+
+ Furthermore, a string Like extension methods allows expressing SQL
+ like conditions.
+
+ cats =
+ session.Query()
+ .Where(c => c.Name.Like("L%l%l"))
+ .ToList();]]>
+
+ This Like extension method is a Linq to NHibernate method only. Trying to call it
+ in another context is not supported.
+
+
+ If you want to avoid depending on the NHibernate.Linq namespace,
+ you can define your own replica of the Like methods. Any 2 or 3 arguments method
+ named Like in a class named SqlMethods will be translated.
+
+
+
+
+
+ Future results
+
+
+ Future results are supported by the Linq provider. They are not evaluated till one gets executed.
+ At that point, all defined future results are evaluated in one single round-trip to database.
+
+ cats =
+ session.Query()
+ .Where(c => c.Color == "black")
+ .ToFuture();
+IFutureValue catCount =
+ session.Query()
+ .ToFutureValue(q => q.Count());
+// Execute them
+foreach(Cat cat in cats)
+{
+ // Do something
+}
+if (catCount.Value > 10)
+{
+ // Do something
+}
+]]>
+
+ In above example, accessing catCount.Value does not trigger a round-trip to database:
+ it has been evaluated with cats enumeration.
+
+
+
+
+ Fetching associations
+
+
+ A Linq query may load associated entities or collection of entities. Once the query is defined, using
+ Fetch allows fetching a related entity, and FetchMany allows
+ fetching a collection.
+
+ oldCats =
+ session.Query()
+ .Where(c => c.BirthDate.Year < 2010)
+ .Fetch(c => c.Mate)
+ .FetchMany(c => c.Kittens)
+ .ToList();]]>
+
+ Issuing many FetchMany on the same query may cause a cartesian product over
+ the fetched collections. This can be avoided by splitting the fetches among
+ future queries.
+
+ oldCatsQuery =
+ session.Query()
+ .Where(c => c.BirthDate.Year < 2010);
+oldCatsQuery
+ .Fetch(c => c.Mate)
+ .FetchMany(c => c.Kittens)
+ .ToFuture();
+IList oldCats =
+ oldCatsQuery
+ .FetchMany(c => c.AnotherCollection)
+ .ToFuture()
+ .ToList();]]>
+
+
+
+ Use ThenFetch and ThenFetchMany for fetching associations
+ of the previously fetched association.
+
+ oldCats =
+ session.Query()
+ .Where(c => c.BirthDate.Year < 2010)
+ .Fetch(c => c.Mate)
+ .FetchMany(c => c.Kittens)
+ .ThenFetch(k => k.Mate)
+ .ToList();]]>
+
+
+
+ Query cache
+
+
+ The Linq provider can use the query cache if it is setup. Refer to
+ for more details on how to set it up.
+
+
+
+
+ Cacheable extension method enables the cache for the query.
+
+ oldCats =
+ session.Query()
+ .Where(c => c.BirthDate.Year < 2010)
+ .Cacheable()
+ .ToList();]]>
+
+
+
+ CacheMode and CacheRegion extension methods set
+ the cache mode and the cache region respectively.
+
+ cats =
+ session.Query()
+ .Where(c => c.Name == "Max")
+ .Cacheable()
+ .CacheRegion("catNames")
+ .ToList();]]>
+
+
+
+ Extending the Linq to NHibernate provider
+
+
+ The Linq to NHibernate provider can be extended for supporting additional SQL functions or
+ translating additional methods or properties to a SQL query.
+
+
+
+ Adding SQL functions
+
+ NHibernate Linq provider feature a LinqExtensionMethod attribute. It allows using an
+ arbitrary, built-in or user defined, SQL function. It should be applied on a method having the same
+ arguments than the SQL function.
+
+
+
+ Then it can be used in a Linq to NHibernate query.
+
+ cats =
+ session.Query()
+ // Pseudo random order
+ .OrderBy(c => (c.Id * rnd).Checksum())
+ .ToList();]]>
+
+ The function name is inferred from the method name. If needed, another name can be provided.
+
+
+
+ It is required that at least one of the parameters of the method call has its value originating
+ from an entity. Otherwise, the Linq provider will try to evaluate the method call with .Net
+ runtime.
+
+
+
+
+ Adding a custom generator
+
+ Generators are responsible for translating .Net method calls found in lambdas to the proper HQL
+ constructs. Adding support for a new method call can be achieved by registering an additional
+ generator in the Linq to NHibernate provider.
+
+
+ If the purpose of the added method is to simply call some SQL function, using
+ will be easier.
+
+
+
+ As an example, here is how to add support for an AsNullable method which
+ would allow to call aggregates which lay yield null without to explicitly
+ cast to the nullable type of the aggregate.
+
+ (this T value) where T : struct
+ {
+ // Allow runtime use.
+ // Not useful for linq-to-nhibernate, could be:
+ // throw NotSupportedException();
+ return value;
+ }
+}]]>
+
+ Adding support in Linq to NHibernate for this custom method requires a generator. For this
+ AsNullable method, we need a method generator, declaring statically its
+ supported method.
+
+ NullableExtensions.AsNullable(0))
+ };
+ }
+
+ public override HqlTreeNode BuildHql(MethodInfo method,
+ Expression targetObject,
+ ReadOnlyCollection arguments,
+ HqlTreeBuilder treeBuilder,
+ IHqlExpressionVisitor visitor)
+ {
+ // This has just to transmit the argument "as is", HQL does not need a specific call for
+ // null conversion.
+ return visitor.Visit(arguments[0]).AsExpression();
+ }
+}]]>
+
+ There are property generators too, and the supported methods or properties can be
+ dynamically declared. Check NHibernate NHibernate.Linq.Functions
+ namespace classes's sources for more examples. CompareGenerator
+ and DateTimePropertiesHqlGenerator are examples of those other cases.
+
+
+ For adding AsNullableGenerator in Linq to NHibernate provider, a new
+ generators registry should be used. Derive from the default one and merge it. (Static
+ declaration of method support case.)
+
+
+
+ In the case of dynamic declaration of method support, another call is required instead of
+ the merge: RegisterGenerator. CompareGenerator
+ illustrates this.
+
+
+ The last step is to instruct NHibernate to use this extended registry. It can be achieved
+ through xml configuration under
+ session-factory node, or by
+ code before building the session factory.
+ Use one of them.
+
+ YourNameSpace.ExtendedLinqToHqlGeneratorsRegistry, YourAssemblyName]]>
+ ();
+// And build the session factory with this configuration.]]>
+
+ Now the following query could be executed, without failing if no Max cat
+ exists.
+
+ ()
+ .Where(c => c.Name == "Max")
+ .Select(c => c.BirthDate.AsNullable())
+ .Min();]]>
+
+ (Of course, the same result could be obtained with (DateTime?)(c.BirthDate).)
+
+
+
+
\ No newline at end of file
diff --git a/doc/reference/modules/query_queryover.xml b/doc/reference/modules/query_queryover.xml
index 70725c8af72..7c3bec1cfdd 100644
--- a/doc/reference/modules/query_queryover.xml
+++ b/doc/reference/modules/query_queryover.xml
@@ -27,7 +27,7 @@
Note: QueryOver is intended to remove the references to 'magic strings'
from the ICriteria API while maintaining it's opaqueness. It is not a LINQ provider;
- NHibernate has a built-in Linq provider for this.
+ NHibernate has a built-in Linq provider for this.