Reputation:
I have a mapped entity, Matter, that has a mapped component, Injury.
The only property on the Injury is DateOfInjury which is a nullable datetime.
When I retrieve the Matter, if the DateOfInjury is null, the component is null.
Thus something like this matter.Injury.DateOfInjury will throw.
Could someone explain if I am doing something obvious to cause this behaviour?
I would have expected that the Injury component gets initialized by nHibernate as an object and that the DateOfinjury property is null.
This would be more flexible i would think?
Upvotes: 15
Views: 6192
Reputation: 7457
https://stackoverflow.com/a/11187173/206297 didn't work for me, but building on it:
public class Injury
{
// ...
private bool dummyFieldToLoadEmptyComponent { get; set; }
}
public class MatterMap : ClassMap<Matter>
{
// ...
Component(x => x.Injury, m =>
{
// ...
m.Map(Reveal.Member<Injury>("dummyFieldToLoadEmptyComponent")).Formula("1=1").ReadOnly();
});
}
The Reveal.Member
bit is just to map a private field in Fluent NHibernate. We want the field private because we don't want that property exposed as part of our public interface to the component. See https://github.com/jagregory/fluent-nhibernate/wiki/Mapping-private-properties. If you don't mind having it public, you could use the less verbose mapping of:
m.Map(x => x.DummyFieldToLoadEmptyComponent).Formula("1=1").ReadOnly();
The Formula
part is because we don't actually want a column in our DB for this. NHibernate will execute that formula when loading the component, and it'll always evaluate to true. I chose 1=1 as I would imagine that's reasonably cross-DB.
Undoubtedly a hack, but seems to work so far for loading empty components and hasn't caused any errors when persisting. Use with discretion though.
Upvotes: 2
Reputation: 2358
This is a technically workable solution. I have tested it with persistance and havent produced transient related issues.
protected internal virtual Injury NullableInjury {get;set;}
public virtual Injury Injury
{
get{return NullableInjury ?? (NullableInjury = new Injury());
}
In Nhibernate map your component to the NullableInjury. This solution allows you to persist without the transient issue reported in @Oliver solution.
Upvotes: 1
Reputation: 95
I've resolved this by adding this property to my component class
public virtual bool _LoadAlways { get { return true; } set { } }
Upvotes: 2
Reputation: 9498
I also ran into the same problem of expecting NHibernate to initialize my component even if all its members are null in the DB. My motivation behind this implementation was to move as much logic concerning my component into the component, not having to deal with it being null or not.
Thanks to this post my search for an explanation why my unit tests were failing for all null values inside the component was short. I fixed this piece in the puzzle by extending the auto-property of my component class ArrivalDay
and assigning a fresh instance myself when null is assigned:
private ArrivalDay _arrivalDay;
public ArrivalDay ArrivalDay
{
get { return _arrivalDay; }
set { _arrivalDay = value ?? new ArrivalDay(); }
}
This works like a charm and means very little overhead on the containing class.
Upvotes: 7
Reputation: 88345
I think that's the default behavior for a component mapping. The NHibernate docs for component say that if all elements of the component are null, the component itself will just be null.
If you only have a single property in the component, it might make sense to just map it as a nullable DateTime property on the Matter class.
Upvotes: 11