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:
- The original EF way of creating an
Initializerwhich inherits fromDropCreateDatabaseAlwaysorDropCreateDatabaseIfModelChanges. You can see the code for this option in my last post. - Using
Migrations, which uses the seed method in the Configuration file which inherits fromDbMigrationsConfiguration
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!


