How often do you see entities mapped with getters and setters for every property, and only a default constructor (either added implicitly by the compiler or explicitly by a developer)? It's not really the best way to map entities, so i just wanted to show a better way of doing this.
Consider the OrderLine entity. It has 4 required properties: Order, Product, UnitPrice and Quantity. It also has one optional property called DiscountPercentage. The Order and Product properties should never be changed after the OrderLine was created. It also has a database Id property which should never be changed either.
This is how the code of the OrderLine class would look like:
public class OrderLine : IIdentifiable<int>
{
public OrderLine(Order order, Product product, decimal unitPrice, int quantity)
{
if (order == null) throw new ArgumentNullException("order");
if (product == null) throw new ArgumentNullException("product");
this.order = order;
this.product = product;
UnitPrice = unitPrice;
Quantity = quantity;
}
// required for NH
protected OrderLine() {}
private int id;
public virtual int Id
{
get { return id; }
}
private Order order;
public virtual Order Order
{
get { return order; }
}
private Product product;
public virtual Product Product
{
get { return product; }
}
public virtual decimal UnitPrice { get; set; }
public virtual int Quantity { get; set; }
public virtual double? DiscountPercentage { get; set; }
}
There is only one public constructor, which takes all of the required properties as parameters. The protected constructor is only there because NHibernate needs it to create run-time proxies (which enable all of the lazy-loading magic). In theory, you can't create instances of the OrderLine entity without its required data.
Also, notice how the Id, Order and Product properties only have a getter, and no setter. These values can no longer be changed by developers once the object is constructed. The UnitPrice and Quantity properties do have setters, because these values can be modified after the entity is created.
The mapping for this class looks like this:
<class name="OrderLine" table="OrderLine" >
<id name="Id" column="Id" type="int" access="nosetter.camelcase" >
<generator class="identity" />
</id>
<many-to-one name="Order" column="OrderId" class="Order" not-null="true" access="nosetter.camelcase" />
<many-to-one name="Product" column="ProductId" class="Product" not-null="true" access="nosetter.camelcase" />
<property name="UnitPrice" column="UnitPrice" type="Decimal" not-null="true" />
<property name="Quantity" column="Quantity" type="int" not-null="true" />
<property name="DiscountPercentage" column="DiscountPercentage" type="double" />
</class>
It's pretty easy... each property that shouldn't be changed after creation is mapped with the nosetter.camelcase access strategy. That means NHibernate uses the private field to set the value directly after creation, but will use the getters whenever it needs to read the data from the entity.
As you can see, without too much trouble you can make sure that your entities always have their required data, and that properties that shouldn't change after creation can't be modified either.
Pingback: Reflective Perspective - Chris Alcock » The Morning Brew #314
Pingback: Arjan`s World » LINKBLOG for March 25, 2009