VALUE OBJECTS AS IDS USING NHIBERNATE
2016 05 08Author: Tomaš Maconko
Many of simple decimal, string or other values can be wrapped into value object to make domain model stronger. It can include validation or simple domain rules that must be applied each time the value object is created. It is immutable so it can only return the calculated value without changing its state.
Value objects can be created using range of technologies and depending on technology the implementation may vary. In this post I will be talking about value objects mapping using NHibernate (FluentNHibernate) and the last problem we faced with entity ID as value object.
In last project we had a class named Project, which included logic depending on ProjectStatus (through StatusId property). First we had IDs as integers and we had no problems until the number of checks for specific IDs was growing.
[csharp]
public class Project : EntityBase
{
…
public virtual int Estimate { get; protected set; }
public virtual int StatusId { get; protected set; }
public virtual void UpdateEstimate(int newEstimate)
{
if (newEstimate < 0)
throw new ArgumentException("New estimate cannot be negative!", nameof(newEstimate));
ProjectStatuses - class for predefined statuses IDs
if (StatusId >= ProjectStatuses.InProgress)
throw new Exception("Project is already in progress!");
Estimate = newEstimate;
}
...
}
public class ProjectStatus : EntityBase
{
…
public virtual int Id { get; protected set; }
public virtual string Name { get; protected set; }
...
}
[/csharp]
We created ProjectStatusId type to hide part of checks inside and include some validation inside.
[csharp]
public class ProjectStatusId : ValueObjectBase
{
public int StatusId { get; protected set; }
//ProjectStatuses - class for predefined statuses IDs
public bool IsInProgress => StatusId >= ProjectStatuses.InProgress.StatusId;
protected ProjectStatusId() { //NHibernate }
public ProjectStatusId(int statusId)
{
if (statusId <= 0)
throw new ArgumentException("Status id value must be a positive integer", nameof(statusId));
...
StatusId = statusId;
}
}
public class ProjectStatus : EntityBase
{
…
public virtual ProjectStatusId Id { get; protected set; }
...
}
public class Project : EntityBase
{
…
public virtual ProjectStatusId StatusId { get; protected set; }
...
public virtual void UpdateEstimate(int newEstimate)
{
...
if (StatusId.IsInProgress)
throw new Exception("Project is already in progress!");
...
}
}
[/csharp]
Before the new type was applied all NHibernate mapping were OK, but after we applied ProjectStatus class the mapping errors appeared. Here we did not find any information about problem solution and tried things by ourselves.
We had already successfully applied the composite-id value objects using CompositeId method in NHibernate mappings. It was containing from two to four different keys inside, but it has been working. So we tried CompositeId for single key property and it worked!
There I provide mappings with ProjectStatusId value object.
[csharp]
public class ProjectMap : ClassMap
{
public ProjectMap()
{
Map(x => x.Description);
Map(x => x.Estimate);
Component(x => x.StatusId, x => x.Map(c => c.StatusId));
}
}
public class ProjectStatusMap : ClassMap
{
public ProjectStatusMap()
{
CompositeId(x => x.Id).KeyProperty(x => x.StatusId);
Map(x => x.Name);
}
}
[/csharp]
Here you see that ProjectStatus has Id mapped using CompositeId and in Project we map StatusId using Component method. Sure, both of them are implemented in a way the NHibernate likes (virtual, protected, empty constructor), but still the result is worthy!
Latest news
-
Microsoft Fabric: addressing data analytics challenges
2024 11 14Find out what Microsoft Fabric is and how you can harness the potential of this platform to make strategic business decisions.
More -
Drupal from 7 to 10: why migration is essential
2024 09 10Read the blog post about Drupal, its different versions, and its benefits. Learn why Drupal migration is essential for your website.
More -
Enterprise architecture: synergy of IT and business goals
2024 09 03Read the blog post about enterprise architecture. Learn about its key benefits, including risk management, regulatory compliance, and improved efficiency.
More