Posts Tagged Int Id
Data Annotations and Entity Framework Code First
I like the code first model of Entity Framework 4 (CTP2 at time of writing). A Domain Entity can be decorated with data annotations which can then be used by the Entity Framework when constructing the database.
I have no concerns adding the System.ComponentModel.DataAnnotations reference to my Domain; I have no intention of changing my DAL and if I change my database it will only be to a different flavour of MS SQL.
There are a number of ‘purposes’ for data annotations but they don’t all sit comfortable within a domain model.
They can represent business rules:
[Key]
public string AccountNumber { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
The KeyAttribute really could be considered a database hint or a business rule.
They can represent hints to the database:
[StoreGenerated(StoreGeneratedPattern.Identity)]
public int AccountNumber { get; set; }
They can also be hints to the UI:
[ScaffoldColumn(false)]
public int Id { get; set; }
Whilst I like the idea of keeping all these annotations neatly tucked up inside my model, the purist in me wants to move the UI hints to a view model and the database hints to an entity configuration class in the data layer.
I think I’ll stick with the KISS approach and keep the annotations within my domain model but reserve the right to change my mind. Any comments / views for or against are welcome.
Entity Classes, IDs and Equality
Posted by John in Methodology on April 22, 2010
I want my entity classes to rely on their ID when checking equality, the ID is populated from the repository when I retrieve an object and automatically generated when I save a new entity.
This poses the problem of how I compare two entities before they have been saved while working with them in my domain, or, when I have ‘newed’ them up myself for unit testing. The answer is to use a transient ID.
Normally an Entity Base class might look like this:
public abstract class EntityBase : IEquatable<EntityBase> {
public virtual int Id { get; protected set; }
public override bool Equals(object other) {
return Equals(other as EntityBase);
}
public override int GetHashCode() {
return Id;
}
public virtual bool Equals(EntityBase other) {
if (other == null) return false;
return other.Id == Id && other.GetType() == GetType();
}
}
If two new objects are created from a derived class then object1.Equals(object2) will be true as Id will be 0 for both objects. To avoid this I need to check if an object has not yet been saved:
private bool IsTransient {
get { return Id == 0; }
}
And just check for referential equality if this is the case:
public virtual bool Equals(EntityBase other) {
if (other == null) return false;
if (IsTransient) return ReferenceEquals(this, other);
return other.Id == Id && other.GetType() == GetType();
}
GetHashCode() needs to be overridden to reflect this:
public override int GetHashCode() {
if (IsTransient) return base.GetHashCode();
return Id;
}
The full code for EntityBase is:
public abstract class EntityBase : IEquatable<EntityBase> {
public virtual int Id { get; protected set; }
private bool IsTransient {
get { return Id == 0; }
}
public override bool Equals(object other) {
return Equals(other as EntityBase);
}
public override int GetHashCode() {
if (IsTransient) return base.GetHashCode();
return Id;
}
public virtual bool Equals(EntityBase other) {
if (other == null) return false;
if (IsTransient) return ReferenceEquals(this, other);
return other.Id == Id && other.GetType() == GetType();
}
}