Contents tagged with NHibernate

  • Lesser-Known NHibernate Features: Future Queries

    Sometimes it makes sense to send several queries at the same time to the database server. This prevents multiple roundtrips and normally can provide results faster. Knowing this, NHibernate offers two features: multiqueries and future queries. Future queries build upon multiqueries and because they use LINQ, which is probably the most common querying API in NHibernate, I will focus in this.

    In order to use future queries, you queue them, by calling the ToFuture() or ToFutureValue() extension methods on any number of queries that you wish to retrieve together:

    1: var futureProducts = session.Query<Product>().Where(p => p.Price > 1000)

    .ToFuture();

       2:  
       3: var futureCustomers = session.Query<Customer>().Where(c => c.Orders.Any()).ToFuture();
       4:  
       5: //no query is sent to the database

    Only after you actually access its results are the queries sent:

       1: var productsCount = futureProducts.Count();

    And the generated SQL is:

       1: select
       2:     product0_.product_id as product1_6_,
       3:     product0_.name as name6_,
       4:     product0_.price as price6_
       5: from
       6:     product product0_
       7: where
       8:     product0_.price>@p0;
       9: select
      10:     customer0_.customer_id as customer1_3_,
      11:     customer0_.name as name3_,
      12:     customer0_.email as email3_
      13: from
      14:     customer customer0_
      15: where
      16:     exists (
      17:         select
      18:             orders1_.order_id
      19:         from
      20:             [
      21:         order] orders1_ where
      22:             customer0_.customer_id=orders1_.customer_id
      23:     );
      24: ;
      25: @p0 = 1000 [Type: Decimal (0)]

    Notice how the two queries are sent at the same time, separated by a semicolon.

    It also works for single values, they can be combined with multi value queries:

    1: var mostExpensiveFutureProduct = session.Query<Product>()

    .OrderByDescending(x => x.Price).Take(1).ToFutureValue();

    The caveat is that this, like multiqueries, is right now only supported in SQL Server, Oracle and MySQL. In all the other cases the results will be retrieved immediately.





    Read more...

  • Lesser-Known NHibernate Features: Entity Mode Map

    This one is a real treat!

    When we use NHibernate or any other O/RM, we normally use classes to represent the database objects (tables or views). In NHibernate, this is called Entity Mode POCOPlain Old CLR Object. NHibernate, however, supports other Entity Mode: Map. This Entity Mode does not use “physical” classes, but instead, dictionaries (implementations of IDictionary)! This makes it great for mapping dynamic database objects without the need for real classes.

    For creating a Map entity, we need to do a slight change in our usual mappings, here is a simple Parent-Child example:

       1: <?xml version="1.0" encoding="utf-8" ?>
       2: <hibernate-mapping namespace="Succinctly.Model" assembly="Succinctly.Model" xmlns="urn:nhibernate-mapping-2.2">
       3:     <class entity-name="Parent" table="`PARENT`">
       4:         <id name="Name" column="`NAME`" type="String" length="50" generator="assigned"/>
       5:         <set name="Children" lazy="true" inverse="true" cascade="all-delete-orphan">
       6:             <key column="`PARENT_NAME`" not-null="true"/>
       7:             <one-to-many entity-name="Child"/>
       8:         </set>
       9:     </class>
      10:     <class entity-name="Child" table="`CHILD`">
      11:         <id name="Name" column="`NAME`" type="String" length="50" generator="assigned"/>
      12:         <many-to-one name="Parent" entity-name="Parent" column="`PARENT_NAME`" not-null="true"/>
      13:     </class>
      14: </hibernate-mapping>

    You might not have noticed that I used entity-name instead of name in the <class> declaration, in <one-to-many> and <many-to-one>; this tells NHibernate that these classes will be mapped as Map, not POCO (the default). Alas, you cannot use mapping by code, because there is no physical class to map.

    OK, so now we have a mapped Parent and Child. We insert them as this:

       1: using (var session = sessionFactory.OpenSession())
       2: {
       3:     var parent = new Hashtable { { "Name", "Parent Name" } };
       4:     parent["Children"] = new HashSet<Object> { new Hashtable { { "Name", "Child Name" }, { "Parent", parent } } };
       5:  
       6:     session.Save("Parent", parent);
       7:     session.Flush();
       8: }

    I am using Hashtable as an IDictionary implementation, but you might as well use Dictionary<TKey, TValue>. It doesn’t really matter.

    As for retrieving, also simple, just use the ISession methods that take an entityName parameter:

       1: var parentProxy = session.Load("Parent", "Parent Name") as IDictionary;
       2:  
       3: var parent = session.Get("Parent", "Parent Name") as IDictionary;

    Each of these IDictionary instances will have an entry that has key “$type$” and contains the entity type name – in our case, either “Parent” or “Child” – as well as entries for each of the other mapped properties, associations and collections:

       1: var name = parent["Name"] as String;
       2: var children = parent["Children"] as ISet<Object>;

    Entity Mode Map supports both HQL and Criteria querying APIs:

       1: var parentsByCriteria = session.CreateCriteria("Parent").Add(Restrictions.Eq("Name", "Parent Name")).List();
       2:  
       3: var parentsByHQL = session.CreateQuery("from Parent where Name = :name").SetParameter("name", "Parent Name").List();

    And it also supports executable HQL:

       1: session.CreateQuery("delete from Child").ExecuteUpdate();

    Cool, don’t you thing? Eat your heart out, Unnamed Framework! Winking smile

    Read more...

  • Lesser-Known NHibernate Features: Mixing Client and Server-Side Calls in Projections

    Another not widely known feature of NHibernate: mixing client and server-side calls.

    To illustrate this, imagine that you want to calculate the difference between a mapped DateTime property and the current time, DateTime.Now. The following query works in NHibernate, but not in other O/RM frameworks:

       1: var timespans = session.Query<Order>().Select(x => DateTime.Now - x.Date).ToList();

    The generated SQL will only be:

       1: select
       2:     order0_.[date] as col_0_0_
       3: from
       4:     [
       5: order] order0_

    But NHibernate will detect that the result needs to be combined with something from the client side and will return a TimeSpan. This mechanism is extensible – more on this in a future post.

    In other O/RMs, which shall remain unnamed, you have to use LINQ to Objects after LINQ to Unnamed Framework:

       1: ctx.Orders.Select(x => new { ElapsedTime = SqlFunctions.DateDiff("HOUR", x.Date, DateTime.Now) }).ToList().Select(x => TimeSpan.FromHours(x.EllapsedTime));

    Pretty cool, don’t you think? Winking smile

    Read more...

  • Lesser-Known NHibernate Features: Mapping a Class to a Query

    Today I start a new series on lesser-known NHibernate features.

    Besides the normal mapping of a class to a table (or view, for that matter), it is also possible to map a class to a query. Do note that this is not the same as having a class mapped to a table and using custom SQL for the INSERTs, UPDATEs, SELECTs or DELETEs, this is something different. This is called Subselect mapping - not to be confused with subselect fetching.

    To demonstrate this, imagine we have a blogging model where a Blog has several Posts. We can map a readonly query between the two as (in HBM.XML):

       1: <?xml version="1.0" encoding="utf-8"?>
       2: <hibernate-mapping namespace="Succinctly.Model" assembly="Succinctly.Model" xmlns="urn:nhibernate-mapping-2.2">
       3:     <class name="BlogPost" mutable="false">
       4:         <subselect>
       5:             <![CDATA[
       6:             SELECT blog_id, (SELECT COUNT(1) FROM post WHERE post.blog_id = blog.blog_id) post_count FROM blog
       7:             ]]>
       8:         </subselect>
       9:         <synchronize table="blog"/>
      10:         <synchronize table="post"/>
      11:         <id column="blog_id" name="BlogId"/>
      12:         <property name="PostCount" column="post_count"/>
      13:     </class>
      14: </hibernate-mapping>

    In mapping by code, it would be:

       1: public class BlogPostMapping : ClassMapping<BlogPost>
       2: {
       3:     public BlogPostMapping()
       4:     {
       5:         this.Subselect("SELECT blog_id, (SELECT COUNT(1) FROM post WHERE post.blog_id = blog.blog_id) post_count FROM blog");
       6:         this.Mutable(false);
       7:         this.Synchronize("blog", "post");
       8:         this.Id(x => x.BlogId, x => x.Column("blog_id"));
       9:         this.Property(x => x.PostCount, x => x.Column("post_count"));
      10:     }
      11: }

    It easy to understand that the class cannot be mutable: it makes no sense to change any of the properties, because they may not map directly to a table.

    Querying is done in exactly the same way:

       1: session.Query<BlogPost>().ToList();

    And the resulting SQL is:

       1: select
       2:     blogpost0_.blog_id as blog1_19_,
       3:     blogpost0_.post_count as post2_19_
       4: from
       5:     ( SELECT
       6:         blog_id,
       7:         (SELECT
       8:             COUNT(1)
       9:         FROM
      10:             post
      11:         WHERE
      12:             post.blog_id = blog.blog_id) post_count
      13:     FROM
      14:         blog ) blogpost0_

    Read more...

  • NHibernate Pitfalls: Specifying Property Types

    This is part of a series of posts about NHibernate Pitfalls. See the entire collection here.

    When you want to specify an NHibernate type (implementation of NHibernate.Type.IType) for a property using mapping by code, you might be tempted to do something like this:

       1: ca.Property(x => x.SomeProperty, x =>
       2: {
       3:     x.Type<StringClobType>();
       4: });

    If you try this, you will get a nasty exception about the type not having a public parameterless constructor. Ouch!

    The thing is: NHibernate types are supposed to be stateless, and therefore it does not make sense to have several instances of a type, that is why NHibernate encourages us to use the static fields defined in the NHibernateUtil class and that is also why most of the built-in types don’t have a public parameterless constructor.

    So, if you want to implement your own types, you can certainly add a public parameterless constructor to them and use the above syntax, but if you are going to use the built-in types, you should instead use:

       1: ca.Property(x => x.SomeProperty, x =>
       2: {
       3:     x.Type(NHibernateUtil.StringClob);
       4: });

    Read more...

  • NHibernate Pitfalls: One Shot Delete and Inverse Collections

    This is part of a series of posts about NHibernate Pitfalls. See the entire collection here.

    When you clear all items in an entity’s collection by calling it’s Clear() method, if it has cascading option all-delete-orphan, NHibernate will then delete (when flushing) all of the collection’s items. That is because it considers them to be children of the entity and we explicitly told NHibernate that the entity no longer has any (very sad, I know! Winking smile).

    Ideally, we would expect NHibernate to only issue a single DELETE, as this:

       1: DELETE FROM children
       2: WHERE parent_id = @p0
       3: /*
       4: AND some_filter_value = @p1
       5: */

    That, however, is not the case for inverse collections, which are the most common ones. In this case, NHibernate issues N DELETEs, one for each entity, which is bad in terms of performance:

       1: DELETE FROM children
       2: WHERE children_id = @p0;
       3:  
       4: DELETE FROM children
       5: WHERE children_id = @p1;
       6:  
       7: -- and so on

    The NHibernate reference has an incorrection, in which it states exactly the opposite:

    “one-shot-delete apply to collections mapped inverse="true"”

    There is an open issue at NHibernate JIRA meant to fix this, https://nhibernate.jira.com/browse/NH-3708, but it is not so simple, so we’ll have to wait! Sad smile

    In the meantime, even though it’s not so intuitive, you can use one of the delete methods I describe in this post.

    Read more...

  • NHibernate Pitfalls: Deletes

    This is part of a series of posts about NHibernate Pitfalls. See the entire collection here.

    While I was writing Deleting Entities in NHibernate, I noticed that actually it referred some pitfalls concerning deleting, so I decided to add them to the proper collection.

    There are several ways to delete entities in NHibernate, as you can see in the referenced post. The problems with each approach are:

    • Using Executable HQL: no cascade to related associations occurs, no events are raised;
    • Using Delete with an entity proxy: forces loading of all cascaded lazy associations before deleting; requires a Flush to apply changes (if it needs to be explicit or not depends on you flush settings);
    • Using Delete with a query string: all items are loaded into the session (not a single DELETE statement), no cascade occurs, no events are raised, no notification about the number of affected records and also requires a flush.

    Read more...

  • NHibernate Pitfalls: Get and Filters

    This is part of a series of posts about NHibernate Pitfalls. See the entire collection here.

    This was suggested a long time ago by Kelly Brownsberger (@kbrowns). What happens is, even if you have filters defined, they are not applied on a call to ISession.Get<T>(). This is by design: you are explicitly asking for an entity with some id, so NHibernate just returns you that. On the other hand, static where restrictions defined at the entity level still apply.

    Read more...

  • NHibernate Pitfalls: Criteria and Collections of Non-Entities

    This is part of a series of posts about NHibernate Pitfalls. See the entire collection here.

    Criteria API – and QueryOver, for that matter, which is just a strongly-typed wrapper around Criteria – cannot work with collections of non-entities: elements, components or dictionaries. If you need to work with those, you need to use one of the other APIs – LINQ, HQL or SQL.

    Read more...