Null value objects in NHibernate

2020-08-15 11:11发布

问题:

I have a person entity containing an Address as a value object:

public Person()
{
    WithTable("Person");
    Id(x => x.Id);
    Component<Address>(x => x.Address, a =>
    {
        a.Map(x => x.Address1);
        a.Map(x => x.Address2);
        a.Map(x => x.Address3);
        a.Map(x => x.Town);
        a.Map(x => x.Postcode);
    });
}

It states in the NHibernate docs that if all the properties of a value object (Address1, Address2 etc) are null, the entire component will be mapped as null (i.e. Person.Address will be null). This is giving me problems in cases where all address fields are null because in my pages where I might have (I'm doing ASP MVC):

<%= Html.TextBoxFor((x => x.Address.Address1))%>

This breaks with a null reference exception. So I'm looking for a clean way to set Address as a new Address() object rather than null if all the fields are empty when I load a Person from the database without doing it manually. I've discounted the following ideas:

Doing null checking in my view (yuk, horrible)

Making database fields not-nullable (I'm dealing with a legacy database)

Anyone any ideas?

回答1:

I don't have any definitive answers creating a method/property accessor that isn't mapped, and that returns a default/null-object if the actual address is null.

public Address GetAddressOrDefault()
{
  return Address ?? new NullAddress();
}

Or similar to the first, create a wrapper for your Address that you use in the view.

public class AddressViewData
{
  private Address address;

  public AddressViewData(Address address)
  {
    this.address = address ?? new NullAddress();
  }

  // expose all address properties as pass-throughs
  public string Street
  {
    get { return address.Street; }
  }
}


回答2:

Thanks to James' ideas (see his answer and comments) I have modified the Address property of my Person entity from:

public virtual string Address { get; set; }

to:

private Address _address;
public virtual Address Address
{
    get { return _address ?? new Address(); }
    set { _address = value; }
}

This has solved my problem, it works, and it seems to work with NHibernate. Yey!



回答3:

In some cases it is very easy to write a NHibernate custom type. Instead of setting the component to null, it would return the null object. I did this in some cases, then you can forget about nulls.

Example of a composite user type.