NHibernate wrongly comparing to null when deleting a component

637 views Asked by At

I currently have an issue when updating a component collection on an entity. It was originally mapped as a bag but that was causing all entries to be deleted and reinserted each time. Changing it to a set has fixed that problem but introduced a new one.

The component type is called Tracking it has a composite key of UserID and ItemID and two properties which are nullable dates. When one of these is created DateRead set to the current time, it is then replaced later with an entry with the new date on.

The underlying SQL NHibernate generates has a where clause which checks that all properties match.

The issue is, the other date DateAcknowledged is often null, and the generated SQL seems to have a syntax error, to do a null check its doing this: = NULL rather than: IS NULL, as shown:

DELETE FROM TrackingTable
   WHERE  ItemId = 'a68f6dea-1c00-42e2-bc40-9fcf01121bd8' /* @p0 */
   AND UserId = 'c8aa41a4-e4c2-4347-ae6e-b48738a53b47' /* @p1 */
   AND DateRead = '2012-01-26T12:56:46.00' /* @p2 */
   AND DateAcknowledged = NULL /* @p3 */

The thing is, the two dates should not be needed at all to determine what to delete. Simply having the where check item ID and user ID would do.

Here is the mapping code where I define the set:

Set(x => x.Trackings,
         mapper =>
                {
                    mapper.Key(k => k.Column("ItemId"));
                    mapper.Table("Tracking");
                    mapper.Access(Accessor.NoSetter);
                },
                collectionMapping => collectionMapping.Component(TrackingMap.Mapping()));

And here is the mapping for the component:

public class TrackingMap
    {
        public static Action<IComponentElementMapper<Tracking>> Mapping()
        {
            return c =>
            {
                c.ManyToOne(x => x.User, a => { a.Column("UserId"); a.ForeignKey("UserId"); });
                c.Property(x => x.DateRead);
                c.Property(x => x.DateAcknowledged, a => a.NotNullable(false));
            };
        }
    }

Is there a way to tell NHibernate to use the keys only on the where clause or for it to compare nulls in the correct way?

2

There are 2 answers

0
Oskar Berggren On BEST ANSWER

This is covered by section 7.2. Collections of dependent objects which notes that this is not supported:

Please note that a composite element mapping doesn't support null-able properties if you're using a <set>. NHibernate has to use each columns value to identify a record when deleting objects (there is no separate primary key column in the composite element table), which is not possible with null values. You have to either use only not-null properties in a composite-element or choose a <list>, <map>, <bag> or <idbag>.

1
Ben Hoffstein On

Please see this answer for a good explanation of how to delete NHibernate entities using criteria. This should allow you to use only ItemId and UserId when determining the items to delete and safely ignore the date comparisons.