Contents tagged with Pitfalls

  • Entity Framework Pitfalls: Collections of Types Other Than ICollection<T> Are Ignored

    If you expose in your entity a collection of a type other than ICollection<T> (or one inheriting from it, such as IList<T>) then it will be ignored. This is a bit absurd, because you might want to expose a collection as read only, where you would probably use IEnumerable<T>. For the record, NHibernate allows that.

    A possible solution is to have a non-public field of type ICollection<T> and to expose it as an IEnumerable<T> property. The problem is that you won’t be able to use the property in LINQ queries, because it is not mapped. And conventions won’t help either, because you cannot configure collections there.


  • NHibernate Pitfalls: HQL Queries With Joins

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

    Normally, in an HQL query, you can omit the select clause, that is, the two queries are identical:

       1: var q1 = session.CreateQuery("from Product"); //both return IList<Product>
       2: var q2 = session.CreateQuery("select p from Product p");

    However, if you add joins, then it’s a whole different matter:

       1: var q3 = session.CreateQuery("from Product p left join p.OrderDetails");             //returns IList<Object[]>
       2: var q4 = session.CreateQuery("select p from Product p left join p.OrderDetails");    //returns IList<Product>

    Worse, queries q3 and q4 will not filter distinct root entities, meaning, you will get the cartesian product of Product x OrderDetail.

    So, you will need to select the root entity (select p), plus add a distinct entity result transformer (Transformers.DistinctRootEntity) to get what you want:

       1: var q5 = session.CreateQuery("select p from Product p left join p.OrderDetails").SetResultTransformer(Transformers.DistinctRootEntity);    //IList<Product>

    This doesn’t happen with LINQ, it always performs a distinct root entity selection, but it also happens with Criteria and QueryOver.

    Thanks to Alexander Zaytsev (@hazzik) who reminded me of this!


  • Entity Framework Pitfalls: Registering Custom Database Functions for LINQ

    Like I said in my previous post, it’s not enough to add a DbFunctionAttribute attribute to a method to have it call a database function. If the function is not a built-in one, it will not be registered in the Entity Framework provider manifest for SQL Server, so it will require registration in the model. You might think, just by looking at the methods in SqlFunctions that all that it took was to add this attribute, but you would be wrong.


  • NHibernate Pitfalls: Refreshing Manually Created Entities Does Not Bring Lazy Properties of Base Types

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

    Suppose you have some properties of an entity, including its id, and you want to refresh its state from the database:

       1: var product = new Product { ProductId = 1 };
       3: //product.Image is null
       5: session.Refresh(product);
       7: //product.Image is null

    Image is a Byte[] and is configured as lazy. The problem is that NHibernate is not capable of returning a proxy for it, because the entity itself is not a proxy.

    This does not happen for associated entities (one-to-one, many-to-one, one-to-many and many-to-many):

       1: var order = new Order { OrderId = 1 };
       3: //order.Customer is null
       5: session.Refresh(order);
       7: //order.Customer is a proxy and accessing the property will load it

    In this case, Customer is another entity, and NHibernate can assign the Order.Customer property a proxy to it.

    Because of this problem, I created a simple extension method that loads all properties. It is even smart enough to use proxies, if we so require it:

       1: public static void InitializeLazyProperties(this ISession session, Object entity, Boolean useProxyWhenPossible = true)
       2: {
       3:     if (entity.IsProxy() == true)
       4:     {
       5:         //if entity is a proxy, use the default mechanism
       6:         NHibernateUtil.Initialize(entity);
       7:     }
       8:     else
       9:     {
      10:         var metadata = session.SessionFactory.GetClassMetadata(entity.GetType());
      11:         var propertiesToLoad = new List<String>();
      13:         for (var i = 0; i < metadata.PropertyNames.Length; ++i)
      14:         {
      15:             if (metadata.GetPropertyValue(entity, metadata.PropertyNames[i], session.ActiveEntityMode) == null)
      16:             {
      17:                 if ((metadata.PropertyTypes[i].IsEntityType == false) || (useProxyWhenPossible == false))
      18:                 {
      19:                     //either load the value
      20:                     propertiesToLoad.Add(metadata.PropertyNames[i]);
      21:                 }
      22:                 else
      23:                 {
      24:                     //or the id of the associated entity
      25:                     propertiesToLoad.Add(String.Concat(metadata.PropertyNames[i], ".id"));
      26:                 }
      27:             }
      28:         }
      30:         var hql = new StringBuilder();
      31:         hql.Append("select ");
      32:         hql.Append(String.Join(", ", propertiesToLoad));
      33:         hql.AppendFormat(" from {0} where id = :id", entity.GetType());
      35:         var query = session.CreateQuery(hql.ToString());
      36:         query.SetParameter("id", metadata.GetIdentifier(entity, session.ActiveEntityMode));
      38:         var result = query.UniqueResult();
      39:         var values = result as Object[] ?? new Object[] { result };
      41:         for (var i = 0; i < propertiesToLoad.Count; ++i)
      42:         {
      43:             var parts = propertiesToLoad[i].Split('.');
      44:             var value = values[i];
      45:             var propertyName = parts.First();
      47:             if (parts.Length > 0)
      48:             {
      49:                 var propertyIndex = Array.IndexOf(metadata.PropertyNames, propertyName);
      50:                 var propertyType = metadata.PropertyTypes[propertyIndex].ReturnedClass;
      52:                 //create a proxy
      53:                 value = session.Load(propertyType, values[i]);
      54:             }
      56:             metadata.SetPropertyValue(entity, propertyName, value, session.ActiveEntityMode);
      57:         }
      58:     }
      59: }

    Of course, it requires that at leat the id property is set. It can be used as:

       1: var order = new Order { OrderId = 360448 };
       3: session.InitializeLazyProperties(order);

    Have fun! Winking smile


  • Entity Framework Pitfalls: Batch Modifications

    Entity Framework does not support batch modifications, that is, UPDATEs or DELETEs of several entities at once. Neither classic nor Code First, not even Entity-SQL.

    For UPDATEs, you have to load each entity and modify it to your liking and then save changes.

    For DELETEs, you don’t need to load an entity, just call Remove with a proxy entity with an assigned primary key property, like this:

       1: var entityToDelete = new MyEntity { Id = 100 };
       2: ctx.MyEntities.Remove(entityToDelete);
       3: ctx.SaveChanges();

    Of course, you can remove several entities at once, just make sure you only call SaveChanges only after Removeing all of them.

    Other alternatives exist:

    1. Plain old SQL, just call Database.ExecuteSqlCommand;
    2. Use a third-party library, such as EntityFramework.Extended, which offers nice strongly-typed methods for both UPDATEs and DELETEs.


  • 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: });


  • 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;
       4: DELETE FROM children
       5: WHERE children_id = @p1;
       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,, 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.


  • 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.


  • 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.


  • 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.