The first thing I thought when I heard about the Code First approach was: Cool, now we can create clean entities without any EF specific code. After the first demo app I saw, that you have to deal with the IDbSet interface, which is placed in the Entity Framework library. (I’m working with EF 4.3)
When you place the entities in your business dll you have to reference the EF library. This is a bit ugly. After some testing I saw that the IDbSet interface implements the generic IQueryable interface.
So it’s possible to cast the IDbSet to a more common interface.
In this example you will see how to use EF code First without referencing the EF lib in your business library.
Here is a picture of my solution folder. The business dll references only the System lib. In the contract folder is the interface for the infrastructure context defined.
The Domain folder contains the entities.
The context interface is very clean. There are no EF specific types used:
public interface IContext
{
IQueryable People { get; set; }
IQueryable Addresses { get; set; }
void Add(T obj) where T : DomainObject;
void Save();
}
And here are the entities:
public class DomainObject
{
public Guid MyId { get; set; }
}
public class Person : DomainObject
{
public string Firstname { get; set; }
public string Lastname { get; set; }
public ICollection Addresses { get; set; }
}
public class Address : DomainObject
{
public string Street { get; set; }
public string City { get; set; }
public int Zip { get; set; }
public virtual Person Person { get; set; }
}
In the infrastructure library I created a context class which implements the IContext interface.
public class Context : DbContext, IContext
{
public Context()
: base("MyDb")
{ }
public IDbSet PersonSet { get; set; }
public IDbSet AddressSet { get; set; }
public IQueryable People
{
get { return this.PersonSet; }
set { this.PersonSet = (IDbSet) value; }
}
public IQueryable Addresses
{
get { return this.AddressSet; }
set { this.AddressSet = (IDbSet)value; }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity()
.HasKey(x => x.MyId)
.Property(x => x.MyId)
.HasColumnName("Id");
base.OnModelCreating(modelBuilder);
}
public void Add(T obj) where T : DomainObject
{
this.Set().Add(obj);
}
public void Save()
{
base.SaveChanges();
}
}
The both public properties PersonSet and AddressSet are used by the EF. But for development only the both properties “People” and “Addresses” are important.
My Entities do not have any entity framework specific Data Annotations like [Key], [ForeignKey] etc.
This definition is made in the OnModelCreating method.
This is it! Here are some test queries:
Database.SetInitializer(new CreateDatabaseIfNotExists()); Business.IContext db = new Infrastructure.Context(); // Create db.Add(new Person() { Id = Guid.NewGuid(), Firstname = "Darko", Lastname = "Micic", Addresses = new List() { new Address() { Id = Guid.NewGuid(), Street = "Unknown", City = "City", Zip = 1234 } } }); db.Save(); // Select person var person = db.People.FirstOrDefault( x => x.Firstname.ToLower() == "darko"); // Select person with address var personWithAddress = from u in db.People.Include("Addresses") where u.Firstname.ToLower() == "darko" select u; // select address var address = from u in db.People where u.Firstname.ToLower() == "darko" select u.Addresses;
















