The core of all applications

Today, I'll talk a little about the core of our application. There are many terms to describe it: business layer/model, entity layer/model, domain layer/model, middle layer... Whatever you want to call it, it still represents the problem you are trying to solve.

Being highly influenced by some articles we read, we mostly use Domain-Driven Design terms. So, our core project is called Peniko.Domain (Peniko is the name of my friends' company). This project started as a collection of POCO classes without much behavior, just enough to accommodate NHibernate's needs, but as we moving toward the higher layers of the application, it's getting more "intelligent". Below is the current class diagram.

Peniko.Domain class diagram

All class names are in English, except for PdvRate class. It should be VatRate (PDV = VAT), but we prefer our local acronym. You'll notice that all classes inherit from Entity<T> and below is how this class looked when it's created. The class is copied from here and renamed to Entity.

public abstract class Entity<T> where T : Entity<T>

{

    private int? _oldHashCode;

 

    /// <summary>

    /// Gets or sets the object Id.

    /// </summary>

    public virtual Guid Id { get; protected set; }

 

    /// <summary>

    /// ...

    /// </summary>

    public override bool Equals(object obj)

    {

        var other = obj as T;

        if (other == null) return false;

 

        // Handle the case of comparing two NEW objects

        var otherIsTransient = Equals(other.Id, Guid.Empty);

        var thisIsTransient = Equals(Id, Guid.Empty);

        if (otherIsTransient && thisIsTransient)

            return ReferenceEquals(other, this);

 

        return other.Id.Equals(Id);

    }

 

    /// <summary>

    /// ...

    /// </summary>

    public override int GetHashCode()

    {

        // Once we have a hash code we'll never change it

        if (_oldHashCode.HasValue) return _oldHashCode.Value;

 

        var thisIsTransient = Equals(Id, Guid.Empty);

 

        // When this instance is transient, we use the base GetHashCode()

        // and remember it, so an instance can NEVER change its hash code.

        if (thisIsTransient)

        {

            _oldHashCode = base.GetHashCode();

            return _oldHashCode.Value;

        }

 

        return Id.GetHashCode();

    }

 

    public static bool operator ==(Entity<T> x, Entity<T> y)

    {

        return Equals(x, y);

    }

 

    public static bool operator !=(Entity<T> x, Entity<T> y)

    {

        return !(x == y);

    }

}

 

There is one more important concept added to Domain project. Repository pattern interfaces. We are reevaluating the decision to have the repository interfaces in domain layer, but for now they are there. The purpose of repositories is to communicate with the mapping layer (load entities, save and delete them). Because CRUD operations are common for all our repositories, we created a base IRepository<T> interface. It looks like this:

public interface IRepository<T> where T : Entity<T>

{

    void Add(T entity);

    void Update(T entity);

    void Delete(T entity);

    T GetById(Guid id);

    IList<T> GetAll();

}

Other interfaces inherit IRepository<T>, and add more methods if necessary. I.e. IProductRepository looks like this:

public interface IProductRepository : IRepository<Product>

{

    Product GetProductByCode(string code);

    Product GetProductByBarCode(string barCode);

}

The classes implementing Repository interfaces are located in Peniko.DataAccess project. I'll talk more about them more in one of the following posts.


0 comments:

Post a Comment