CampusNexus Entity Framework

CampusNexus Entity Framework

Note: The example service used in this solution can be found in TFS at this location: $/Framework/Internal/ServiceExample

What is an Entity?

In CampusNexus, an Entity represents a person, place, or thing such as a Course, Task or Campaign.  Entities only contain the properties associated with itself such as first name, last name or city.  The verbs associated with an entity (e.g. Save, PostFinalGrades, or AddToCampaign) are exposed by a corresponding Service or EntityService.

All entities in CampusNexus inherit from the Cmc.Core.EntityModel.Entity abstract base class.  The Entity base class contains all the logic required for maintaining the state of an entity and its children while it is being modified in business logic, on the client, or by an external system.

As you can see from the class diagram below, Entity implements System.ComponentModel.INotifyPropertyChanged as well as Cmc.Core.EntityModel.IStateful to assist in the notification and maintenance its state:

EntityClassDiagram

Below is a brief description of the properties and methods exposed by the Entity type.

Properties

  • EntityState: gets or sets the state of an entity
    • Added: the entity is new, an INSERT database operation will be performed
    • Removed: the entity has been removed, a DELETE operation will be performed
    • Modified: the entity has been modified, an UPDATE database operation will be performed
    • Unchanged: the entity is unchanged, no database operation will be performed
  • ExtendedProperties: represents a collection of dynamic entity properties such as School Defined Fields.
  • ModifiedProperties: represents a read-only collection of property names that have been modified since the entity was last retrieved.
  • OriginalState: represents the entity’s original state serialized in a byte[].  This property is used to round-trip the entity state from the client to the server and is not intended to be updated directly in code.
  • OriginalValues: represents the original values of an entity as a dictionary.

Methods

  • AcceptChanges: accepts all current changes and sets the entity’s state to Unchanged.  This does not perform a database operation.
  • GetOriginalValue: gets the original value of a specified property
  • HasChanged: returns true if an entity (or its children) have changed; else false

 Example Implementation: Person

Now that you have a good understanding of what an Entity is, lets take a look at what an implementation might look like.  For this example, we will be using two entities:

  • PersonEntity – Represents a person
  • AddressEntity – Represents an person’s address

A Person can have zero-or-more addresses, and for this example we want the addresses to be updated with the person as a single unit-of-work.  A single unit-of-work means all the persistence operations associated with the entity and its children are enlisted within the same database transaction.  For example, take a look at the C# code below:

Below you will find the class diagrams and implementations of the PersonEntity and AddressEntity types:

 PersonClassDiagram

 

A few things to notice about these types

  1. Both types inherit Cmc.Core.EntityModel.Entity which enables serializable state tracking and property change events.
  2. Both types implement Cmc.Core.ComponentModel.IIdentifiable to automate the maintenance of identifiers (or Id).  This is optional but recommended.
  3. Both types implement Cmc.Core.ComponentModel.IAuditable to automate the maintenance of properties such as CreatedDateTime, LastModifiedDateTime, and LastModifiedUserId.  This is optional.
  4. All properties declare an associated EntityProperty as a public static readonly field.  The importance of these fields is explained in detail below when we start discussing the maintenance of entity state, but in short they provide metatdata as well as type safety when:
    1. querying a property’s state:  if (entity.HasChanged(Person.FirstNameProperty)) { }
    2. identify a property within a property change event:   if (args.PropertyName == PersonEntity.FirstName.Name){}
  5. All properties defer to Entity::GetValue() within the “getter” and Entity::SetValue() within the “setter”.  This allows the base Entity to raise events when property values change as well as maintain serializable state tracking.
  6. Both types and their properties are annotated with the System.Runtime.Serialization attributes such as DataContract and DataMember.  These attributes are required for instances to be serializable and versionable when exposed as arguments through ASP.NET WebAPI or WCF.
  7. Both types and their properties are annotated with System.ComponentModel.DataAnnotations such as Required, StringLength, MaxLength, etc.  These attributes are used to assist in the validation of the entity.
  8. Both types and their properties are annotated with System.ComponentModel.DataAnnotations.Schema attributes such as Table, Column, Key, ForeignKey, etc.  These attributes are used to assist in the persistence of the entity.
  9. Both types declare a RowVersion property annotated with the System.ComponentModel.DataAnnotations.TimestampAttribute. This property automatically enables optimistic concurrency during persistence of the entity.
  10. Child collections, such as Addresses on PersonEntity, are defined as Cmc.Core.EntityModel.EntityCollection<T>.  EntityCollection provides state tracking of child Entites.

Maintaining Entity State

Now that you have an example of some concrete implementations of Entity, lets discuss how we maintain state within our unit of work.  This is extremely important, as it defines the database operations that will be performed against the entity during persistence.

The state of an entity is maintained by the EntityState property on Entity.  Enity::EntityState is of enumeration type Cmc.Core.EntityModel.EntityState that contains these values:

When updating the entity in .NET, EntityState will automatically be maintained for you.  See the below code with assertions for details on how EntityState behaves based on operations performed on PersonEntity:

Below is an example of the behaviors associated with working with child entities using EntityCollection<T>:

Additional Interfaces

IIdentifiable

Most Entities have an identifier, or and ID.  Although the framework’s EntityService<T> does not require types to implement IIdentifiable, the framework will maintain this identifier for you as long as you implement IIdentifable on your entity types.

 

IAuditable

Most Entities in CampusNexusStudent contain properties associated with auditing .  If you implement IAuditable, the CreatedDateTime, LastModifiedDateTime, and LastModifiedUserId will be maintained for you by a framework-level event handler associated with the Saving event of an entity.

 

Leave a Reply

Skip to toolbar