Skip to content

Entities

Craig Fowler edited this page Feb 25, 2020 · 2 revisions

CSF.Entities packages some otherwise-boilerplate logic to describe domain entities (that is, persistent objects mapped to a data-store via an ORM) in a consistent manner. To use this library, your entity classes must implement the interface IEntity.

The Entity<T> base class

If you don't mind using a base class, then you may use Entity<T> to implement the IEntity interface. The type parameter T indicates the type of the identity/primary key value for this entity. Typical choices are long, int or Guid.

The entity base class exposes two protected properties related to the identity; it is up to the developer whether to expose these publicly or not on concrete entity implementations.

Identity objects

Objects derived from IEntity have an extension method available in the CSF.Entities namespace: GetIdentity(). This returns an object of type IIdentity<T>, where the type parameter T is the type of the entity for which the identity was created.

The identity object is a consistent way to represent the identity of an entity object, without concerning oneself with the underlying data-type of the identity value.

Identities may also be created directly and parsed from other data-types, such a strings.

// In each case, 'id' will be IIdentity<Person>

// Get an identity from an entity instance
var id = aPerson.GetIdentity();

// Create an identity directly
var id = Identity.Create<Person>(5);

// Parse a string as an identity
var id = Identity.Parse<Person>("5");

Identity equality for entities

Neither the entity base class or the IEntity interface change the default way that equality works for entity classes. To compare entities for identity-equality, use either of:

  • An instance of EntityIdentityEqualityComparer.
  • The extension method IdentityEquals(IEntity) in the CSF.Entities namespace.

Put simply, entity objects are identity-equal if their identities are equal (see below).

Equality for identity objects

Identities are immutable value objects (not to be confused with value types; they are classes, not structs). As such, their default Equals method has been overridden.

Two identity objects are equal if their identity values are equal and their entity types are compatible. Two entity types are deemed compatible if either:

  • They are the same type
  • Both types share a common base type, which:
    • Is not System.Object
    • Is not decorated with [IgnoreForIdentityEquality]

Warning: Avoid == for comparing identities

Do not use the == operator to compare identity instances for equality. For covariance to work, identities are referenced and assigned by the interface IIdentity<T> and not by their concrete type. This means that operator overloads would not be used, even if they did exist. To avoid confusion, the == operator has intentionally not been overloaded for identity types.

To correctly compare identities for equality where either might be null, use the Object.Equals(object, object) method.

The [IgnoreForIdentityEquality] attribute

An attribute is available for entity classes which is useful in two scenarios:

  • If you wish to create your own general base class for all entity types
  • If your ORM mapping strategy means that 'sibling' classes (subclasses of a common base entity) could coexist with duplicate identity/primary key values

In these cases, those base classes should be decorated with [IgnoreForIdentityEquality]. This will prevent the identity-equality algorithm from treating entities as equal when they are not.

Clone this wiki locally