Tag Archives: Entity Framework

Related Entities Already Attached to the Context Being Automatically Referenced

I stumbled across something today which had me quite stumped for a while and is worth blogging about. I feel like this is something I should have known, and probably did know, when I first read books and articles on the Entity Framework. But alas, if I did know, I had forgotten.

I was working with a repository which had a DbContext for data access, with both lazy loading and proxy enablement set to false. So, no proxies and no lazy loading.

I was iterating a list which did not include any “include” statements. So no related entities of the entities in the current list should have been eager loaded. However, I was noticing that there were related entities loaded for the entities in the list. Not all, but one particular related entity.

I had to get to the bottom of this, so I created a solution which used the raw DbContext, to rule out anything happening in the repository’s code that was loading the entities. (Note, I did read through the repository code and could not see any culprit.)

If you look at Figure 1 below, a list of Person entities is displayed and I have maximised one as an example (that of Terry Halpin). You can see that the Lendings related entity is null. This is exactly what I would expect from a DbContext, where there is no eager loading involved (no “includes”). So, for a while there I was convinced that something in the Repository was eager loading related entities, when not actually called upon to do so. And that would be bad.

Figure 1 - No Value for Lendings Related Entity

Figure 1 – No Value for Lendings Related Entity

This bounced around in my head for a while and I was not convinced. Then, I had a “penny drop” moment when debugging the offending code ->>> perhaps the Lendings were being retrieved and brought into memory (Local) at an earlier point in the program’s flow. I knew, for sure, that other things were being retrieved previously. So, if they are already in memory, were they automatically being referenced by the new objects, that were being loaded into memory, without any “include” statements?

So I went back to my small experimental solution to test my theory. That theory being:

If an entity is a related entity (the “Related Entity”) of another entity (the “Primary Entity”), and that Related Entity is already in memory by the time the Primary Entity is itself loaded, then the Related Entity will accordingly be a non-null member of the Primary Entity.

Now THAT was a mouthful, so I will elaborate with a screenshot. But before we look at it, quickly look back to Figure 1, where all that was being retrieved was a Queryable of Person entities.

Now look at Figure 2:

Figure 2 - Lendings Related Entity is now populated

Figure 2 – Lendings Related Entity is now populated

There are 2 things to note:

  1. Before retrieving the Person entities, I have retrieved a list of Lending entities and forced the loading of that list, from the database, by calling ToList().
  2. Now, if you look at the same entity which I expanded in the Person list (Terry Halpin), you will see that the Lendings related entity is populated (not null). But I have not used the includes extension-method to eager load those Lendings.

Now I’m going to go walk my dog.

A Unit of Work with Repositories Underpinned by DbContext – The DAL

An index of the HomeLibrary application posts can be found here.

I want to have a quick discussion about data access, as I have already re-factored this code in the HomeLibrary application. Originally, I just put in place a couple of simple repositories which looked like this:
Generalised Base Class

public abstract class RepositoryBase<T, TCxt> : IDisposable
	where T : class
	where TCxt : DbContext, new()
{
	public DbContext Context;
	public DbSet<T> Items;

	protected RepositoryBase()
		: this(new TCxt())
	{
		
	}

	protected RepositoryBase(TCxt context)
	{
		Context = context;
		Items = Context.Set<T>();
	}

	public T Create()
	{
		CheckDisposed();
		return Items.Create();
	}

	public void Add(T item)
	{
		CheckDisposed();
		Items.Add(item);
		Context.SaveChanges();
	}

	public T GetById(int id)
	{
		CheckDisposed();
		var set = Items.Find(id);
		return set;
	}

	public void Remove(T item)
	{
		CheckDisposed();
		Items.Remove(item);
		Context.SaveChanges();            
	}

	public void Update(T item)
	{
		CheckDisposed();

		var entry = Context.Entry(item);
		if (entry.State == EntityState.Detached)
		{
			Items.Attach(item);
			entry.State = EntityState.Modified;
		}
		Context.SaveChanges();            
	}
	
	public IList<T> GetAll()
	{
		CheckDisposed();
		return Items.ToList();
	}

	public abstract void CheckDisposed();

	public void Dispose()
	{
		if (!Context.TryDispose()) return;
		Context = null;
		Items = null;
	}
}

Domain-centric Repositories would Inherit from the Base Class

public class BookRepository : RepositoryBase<Book, HomeLibraryContext>, IBookRepository 
{
	public BookRepository()	{ }

	public BookRepository(HomeLibraryContext ctx) 
		: base(ctx)
	{ }

	public override void CheckDisposed()
	{
		if (Context == null)
		{
			throw new ObjectDisposedException("BookRepository");
		}
	}
}

I had a feeling there would be some better stuff out there which facilitated the repository-style access to the data via the DbContext. After a bit of searching, I stumbled upon this answer at stackoverflow. You can go there to read the code if you like (or here for my version), as it is quite large and not practical for me to repeat here.

It uses a unit of work to centralise access through a number of repositories. I liked the idea of this and when I went through the code, I recognised that it was quite sophisticated and written by someone who had really thought it through (and probably incorporated some hard learnt lessons). I made a couple of changes which I preferred, as I don’t just accept someone else’s code without scrutiny. I tagged that revision of the source DataAccessAndDomain_1.1, so it is available to download or read online.

This is definitely overkill for a simple book-lending application. However, I want to endeavour to use enterprise best practices for this sample application.

Migrations v.s DatabaseInitializer

An index of the HomeLibrary application posts can be found here.

As I mentioned in my previous post, I ran into an interesting situation with Entity Framework 6. It went a little like this…

I kicked off my data layer with some domain objects, a HomeLibraryContext class (deriving from DbContext) and a HomeLibraryInitializer class which inherits from DropCreateDatabaseAlways. The HomeLibraryInitializer contains a Seed method which inserts some data into the newly created database.

I also decided that I was going to use EntityFramework Migrations to enable me to make changes to the database as I evolve my domain model. To that end, I enabled migrations on the HomeLibrary.EF project using the Package Manager Console and created the first Migration:

internal sealed class Configuration : DbMigrationsConfiguration<Db.HomeLibraryContext>
{
	public Configuration()
	{
		AutomaticMigrationsEnabled = false;
	}

	protected override void Seed(Db.HomeLibraryContext context)
	{
		new List<Person>
			{
				new Person {FirstName = "Terry", LastName = "Halpin"},
				new Person {FirstName = "Alan", LastName = "Turing"}
			}.ForEach(p => context.People.Add(p));

		context.SaveChanges();
	}
}

The initial Migration:

public partial class Initial : DbMigration
{
	public override void Up()
	{
		CreateTable(
			"dbo.BookCovers",
			c => new
				{
					Id = c.Int(nullable: false, identity: true),
					BookId = c.Int(nullable: false),
					Edition = c.Int(nullable: false),
					Cover = c.Binary(maxLength: 4000),
				})
			.PrimaryKey(t => t.Id)
			.ForeignKey("dbo.Books", t => t.BookId, cascadeDelete: true)
			.Index(t => t.BookId);
		
		CreateTable(
			"dbo.Books",
			c => new
				{
					Id = c.Int(nullable: false, identity: true),
					Title = c.String(nullable: false, maxLength: 4000),
					Edition = c.Int(nullable: false),
					PublisherId = c.Int(nullable: false),
					TypeOfBook = c.Int(nullable: false),
				})
			.PrimaryKey(t => t.Id)
			.ForeignKey("dbo.Publishers", t => t.PublisherId, cascadeDelete: true)
			.Index(t => t.PublisherId);
		
		CreateTable(
			"dbo.People",
			c => new
				{
					Id = c.Int(nullable: false, identity: true),
					Email = c.String(nullable: false, maxLength: 4000),
					IsAuthor = c.Boolean(nullable: false),
					FirstName = c.String(nullable: false, maxLength: 4000),
					LastName = c.String(nullable: false, maxLength: 4000),
					Sobriquet = c.String(maxLength: 4000),
				})
			.PrimaryKey(t => t.Id);
		
		CreateTable(
			"dbo.Lendings",
			c => new
				{
					Id = c.Int(nullable: false, identity: true),
					BookId = c.Int(nullable: false),
					BorrowerId = c.Int(nullable: false),
					DateLent = c.DateTime(nullable: false),
					DueDate = c.DateTime(),
					ReturnDate = c.DateTime(),
				})
			.PrimaryKey(t => t.Id)
			.ForeignKey("dbo.Books", t => t.BookId, cascadeDelete: true)
			.ForeignKey("dbo.People", t => t.BorrowerId, cascadeDelete: true)
			.Index(t => t.BookId)
			.Index(t => t.BorrowerId);
		
		CreateTable(
			"dbo.Comments",
			c => new
				{
					Id = c.Int(nullable: false, identity: true),
					BookId = c.Int(nullable: false),
					CommentText = c.String(nullable: false, maxLength: 4000),
				})
			.PrimaryKey(t => t.Id)
			.ForeignKey("dbo.Books", t => t.BookId, cascadeDelete: true)
			.Index(t => t.BookId);
		
		CreateTable(
			"dbo.Publishers",
			c => new
				{
					Id = c.Int(nullable: false, identity: true),
					Name = c.String(nullable: false, maxLength: 4000),
				})
			.PrimaryKey(t => t.Id);
		
		CreateTable(
			"dbo.PersonBooks",
			c => new
				{
					Person_Id = c.Int(nullable: false),
					Book_Id = c.Int(nullable: false),
				})
			.PrimaryKey(t => new { t.Person_Id, t.Book_Id })
			.ForeignKey("dbo.People", t => t.Person_Id, cascadeDelete: true)
			.ForeignKey("dbo.Books", t => t.Book_Id, cascadeDelete: true)
			.Index(t => t.Person_Id)
			.Index(t => t.Book_Id);
		
	}
	
	public override void Down()
	{
		DropForeignKey("dbo.Books", "PublisherId", "dbo.Publishers");
		DropForeignKey("dbo.BookCovers", "BookId", "dbo.Books");
		DropForeignKey("dbo.Comments", "BookId", "dbo.Books");
		DropForeignKey("dbo.Lendings", "BorrowerId", "dbo.People");
		DropForeignKey("dbo.Lendings", "BookId", "dbo.Books");
		DropForeignKey("dbo.PersonBooks", "Book_Id", "dbo.Books");
		DropForeignKey("dbo.PersonBooks", "Person_Id", "dbo.People");
		DropIndex("dbo.Books", new[] { "PublisherId" });
		DropIndex("dbo.BookCovers", new[] { "BookId" });
		DropIndex("dbo.Comments", new[] { "BookId" });
		DropIndex("dbo.Lendings", new[] { "BorrowerId" });
		DropIndex("dbo.Lendings", new[] { "BookId" });
		DropIndex("dbo.PersonBooks", new[] { "Book_Id" });
		DropIndex("dbo.PersonBooks", new[] { "Person_Id" });
		DropTable("dbo.PersonBooks");
		DropTable("dbo.Publishers");
		DropTable("dbo.Comments");
		DropTable("dbo.Lendings");
		DropTable("dbo.People");
		DropTable("dbo.Books");
		DropTable("dbo.BookCovers");
	}
}

I then started running into difficulties. Strange things were happening and the SQL Server Compact database was not responding to my Migrations commands in the way I expected. So, I turned to Google.

As it turns out, there are two options for seeding the database using Code First and they are mutually exclusive:

  1. The original EF way of creating an Initializer which inherits from DropCreateDatabaseAlways or DropCreateDatabaseIfModelChanges. You can see the code for this option in my last post.
  2. Using Migrations, which uses the seed method in the Configuration file which inherits from DbMigrationsConfiguration

For this project, I preferred the original EF way as I have found it much simpler to work with. I am, however, going to try and have my cake and eat it. When I made this decision, I found that all I had to do to disable Migrations was to exclude the Migrations directory from my solution. However, if I do want to change the schema again and use Migrations to create a Migration, I can just include that folder again, comment out the code which sets the DatabaseInitializer and create a new Migration based on the current state of the domain classes. Let’s see whether this approach continues to work!