I was browsing the SharpArch Northwind sample earlier, just out of curiosity, and had a few eyebrow moments.
Below are two sample of entities from the solution.
Northwind.Core.Order.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpArch.Core.PersistenceSupport;
using SharpArch.Core.DomainModel;
using SharpArch.Core;
namespace Northwind.Core
{
public class Order : Entity
{
/// <summary>
/// This is a placeholder constructor for NHibernate.
/// A no-argument constructor must be avilable for NHibernate to create the object.
/// </summary>
protected Order() { }
public Order(Customer orderedBy) {
Check.Require(orderedBy != null, "orderedBy may not be null");
OrderedBy = orderedBy;
}
public virtual DateTime? OrderDate { get; set; }
public virtual string ShipToName { get; set; }
public virtual Customer OrderedBy { get; protected set; }
/// <summary>
/// Should ONLY contain the "business value signature" of the object and not the Id,
/// which is handled by <see cref="Entity" />. This method should return a unique
/// int representing a unique signature of the domain object. For
/// example, no two different orders should have the same ShipToName, OrderDate and OrderedBy;
/// therefore, the returned "signature" should be expressed as demonstrated below.
///
/// Alternatively, we could decorate properties with the [DomainSignature] attribute, as shown in
/// <see cref="Customer" />, but here's an example of overriding it nonetheless.
/// </summary>
public override bool HasSameObjectSignatureAs(BaseObject compareTo) {
Order orderCompareTo = compareTo as Order;
return orderCompareTo != null && ShipToName.Equals(orderCompareTo.ShipToName) &&
(OrderDate ?? DateTime.MinValue).Equals((orderCompareTo.OrderDate ?? DateTime.MinValue)) &&
OrderedBy.Equals(orderCompareTo.OrderedBy);
}
}
}
Northwind.Core.Product.cs
using SharpArch.Core.DomainModel;
using NHibernate.Validator.Constraints;
namespace Northwind.Core
{
public class Product : Entity
{
public Product() { }
/// <summary>
/// Creates valid domain object
/// </summary>
public Product(string name, Supplier supplier) {
Supplier = supplier;
ProductName = name;
}
[DomainSignature]
[NotNullNotEmpty]
public virtual string ProductName { get; set; }
[DomainSignature]
[NotNull]
public virtual Supplier Supplier { get; protected set; }
public virtual Category Category { get; set; }
}
}
Things I noticed:
-
In one constructor, they check the input. In the other, they don’t. Is there a reason for this?
-
In one instance, where a field input via the constructor is checked before assignment, they leave the property open for changing, without applying the same logic. Isn’t this leaving the entity open for error?
-
They put an emphasis on leveraging automatic properties, including when dealing with has-many collections. There is no wrapping logic. Was this simply for examples sake?
Anyway, the question is this:
Are these good or bad examples?
If they are good examples, I believe I was over-engineering my entities. If it was bad, then why did they put it in their example?