CategoryEntity Framework

EntityFrameworkCore and IDesignTimeDbContextFactory

In one of my first attempts on using EntityFrameworkCore I quickly ran into the following error
This problem appears when your dbcontext is in a different project than your web project.

Unable to create an object of type ‘….DbContext’. Add an implementation of ‘IDesignTimeDbContextFactory’ to the project, or see https://go.microsoft.com/fwlink/?linkid=851728 for additional patterns supported at design time.

I fixed this by implementing the IDesignTimeDbContextFactory as follows:

    public class YourDbContextDesignTimeFactory : IDesignTimeDbContextFactory<YourDbContext>
    {
        public BuildMonitorDbContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<YourDbContext>();
            optionsBuilder.UseSqlServer(@"ConnectionStringGoesHere");

            return new YourDbContext(optionsBuilder.Options);
        }
    }

A better solution would be storing the connection string in your appsettings file.

        IConfigurationRoot configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json")
            .Build();
 
        var builder = new DbContextOptionsBuilder<YourDbContext>();
 
        var connectionString = configuration.GetConnectionString("YourDbContext");

The appsettings.json file would look something like

{
  "ConnectionStrings": {
    "YourDbContext": "ConnectionStringGoesHere"
  }
}

EF Code First Index Column not created

A while back I tried to create a unique index on a column.
The configuration file looked something like this.

    public class DepartmentEntityConfiguration : EntityTypeConfiguration<Department>
    {
        public DepartmentEntityConfiguration()
        {
            HasKey(p => p.Id);
            Property(p => p.Alias).IsRequired().HasColumnAnnotation("Alias", new IndexAnnotation(new IndexAttribute("IX_Alias") { IsUnique = true }));
            Property(p => p.Name).IsRequired();
        }
    }

This resulted in the following migration.

            CreateTable(
                "dbo.Departments",
                c => new
                    {
                        Id = c.Guid(nullable: false),
                        Alias = c.String(
                            annotations: new Dictionary<string, AnnotationValues>
                            {
                                { 
                                    "Alias",
                                    new AnnotationValues(oldValue: null, newValue: "IndexAnnotation: { Name: IX_Alias, IsUnique: True }")
                                },
                            }),
                        Name = c.String(nullable: false),
                    })
                .PrimaryKey(t => t.Id);

Which seemed fine. It looked like it did what it supposed to do.
When the migration was run, no index or whatsoever. So I started googling about indexes and I came across the following:

Columns that are of the large object (LOB) data types ntext, text, varchar(max), nvarchar(max), varbinary(max), xml, or image cannot be specified as key columns for an index.

So I limited the Alias to 50 characters in the configuration file:

    public class DepartmentEntityConfiguration : EntityTypeConfiguration<Department>
    {
        public DepartmentEntityConfiguration()
        {
            HasKey(p => p.Id);
            Property(p => p.Alias).IsRequired().HasMaxLength(50).HasColumnAnnotation("Alias", new IndexAnnotation(new IndexAttribute("IX_Alias") { IsUnique = true }));
            Property(p => p.Name).IsRequired();
        }
    }

But still no Index. So I continued my search on the internet and I Finally found the problem.
It is the name of the HasColumnAnnotion method. This should be set to “Index” when you want to create an Index. This seems a bit unnecessary to me when the second argument is an IndexAnnotation. So once again I changed my configuration file:

    public class DepartmentEntityConfiguration : EntityTypeConfiguration<Department>
    {
        public DepartmentEntityConfiguration()
        {
            HasKey(p => p.Id);
            Property(p => p.Alias).IsRequired().HasMaxLength(50).HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("IX_Alias") { IsUnique = true }));
            Property(p => p.Name).IsRequired();
        }
    }

The migration file generated:

            CreateIndex("dbo.Departments", "Alias", unique: true);

So now I know that the HasColumnAnnotation name is fixed on “Index”, I would recommend creating an extension method for creating unique indexes:

    public static class PrimitivePropertyConfigurationExtensions
    {
        public static PrimitivePropertyConfiguration IsUnique(this PrimitivePropertyConfiguration configuration)
        {
            return configuration.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute { IsUnique = true }));
        }
    }

And you can use it as follows:

    public class DepartmentEntityConfiguration : EntityTypeConfiguration<DepartmentState>
    {
        public DepartmentEntityConfiguration()
        {
            HasKey(p => p.Id);
            Property(p => p.Alias).IsRequired().HasMaxLength(50).IsUnique();
            Property(p => p.Name).IsRequired();
        }
    }

Keep EntityFramework state objects valid by encapsulating it in domain entities

There are already a lot of great posts (f.e. by Vaughn Vernon) about how to use EntityFramework with Domain Entities.
So why am I writing about? Because I think it is important not to leak your state objects to your entire application.

EntityFramework cannot map private fields, so you need to make all mapped properties public.
The domain entity is responsible to make sure that the state object is always in a valid state.
EntityFramework does not work with ValueObjects, so you cannot use ValueObjects in a nice way in your state. So another plus for Domain Entities.
A state object does not necessarily need to be an entity, it could also be a ValueObject when you don’t care about uniquely identifying the ValueObject. The state will still have an id, but you can hide it in your ValueObject.

In this example I’m talking about products, they are stored with entity framework as ProductState entities.

    public class ProductState
    {
        public Guid Id { get; set; }
        public string ProductCode { get; set; }
        public string Title { get; set; }
    }

Constructing

It starts with the constructors. I usually create two constructors, one for reviving the entity from the database and one for newly constructing the entity. Every constructor should result in a valid Product and ProductState.
The following constructor revives the product from it’s state.

    public class Product
    {
        private readonly ProductState _state;
        public Product(ProductState productState)
        {
            Assert.NotNull(productState, nameof(productState));

            _state = productState; 
        }
    }

The state is provided from the repository. It is already in valid state, a null check is sufficient.
Noticed the nameof? This new trick can come in very handy f.e. for logging purposes.
In this example, a product is valid when it has a ProductCode, this is the unique identifier of the product. The constructor for creating a new product is as follows:

    public class Product
    {
        private readonly ProductState _state;
        public Product(ProductCode productCode)
        {
            Assert.NotNull(productCode, nameof(productCode));

            _state = new ProductState
            {
                Id = Guid.NewGuid(),
                ProductCode = productCode.Value,
            };
        }
    }

The Product entity is responsible for instantiating a ProductState and make sure it is in valid state. The Id is the primary key for EntityFramework, the product code is used as surrogate identifier.

Exposing data

Now that we have instantiated a Product, we can use it in our application.
The private (and readonly) state is used as backing variable for every get or set method/property.
The methods in Product look as follows

        public ProductCode GetProductCode()
        {
            return new ProductCode(_state.ProductCode);
        }

        public string GetProductTitle()
        {
            return _state.ProductTitle;
        }

        public void SetProductTitle(string title)
        {
            Assert.NotNull(title, nameof(title));
            if (title.Length > 255)
            {
                throw new ArgumentException("ProductTitle cannot be more than 255 characters.");
            }
            _state.ProductTitle = title;
        }

There is no Set method for ProductCode? Correct! The ProductCode is the identifier for the Product, it is immutable. A different product code is a different product, so this requires instantiating a new/differnt Product.
The ProductTitle does not identifies the Product, so there is a set method for the ProductTitle. In this set method, there are some business rules; in this example the ProductTitle cannot be null and should not be more than 255 characters. This makes sure that the state object could never get an invalid title in the ProductTitle property.
I prefer void as return type for set methods. When the provided data is invalid I throw exceptions. Returning a bool to indicate if the operation went succesfull has some disadvantages, f.e.:
– It does not give any detail of what went wrong
– It suggests we can still continue normally.
In this example I use methods for the Get operations, this could as well have been properties.

Attaching the State Entity to EntityFramework

Unfortunately, There is a downside to this. Now that the Product creates the ProductState, we need to attach it to the DbContext before EntityFramework will pick it up.
So we do need to expose the inner state entity. I always try to make it internal so not everybody can reach it, but there are (many) situations when internal is not enough and you need to make it public.

        internal ProductState InnerState
        {
            get { return _state; }
        }

Updating EntityFramework State objects before DbContext Saves their state

In most of the projects, we use Entity Framework as ORM. It works ok in most cases.
We always try to hide the state object as much as possible, we try to encapsulate the state objects with Domain Entities. Repositories can be used to retrieve these Domain Entities.

For a project, we needed to store serialized data in a state object. These are some reasons why we chose to store data serialized:

  • The data structure can vary by entity
  • There is no need to query this data
  • It is a complex structure and would require lots of tables to store it deserialized

We need to make sure this serialized data is always up to date (serialized) before saving.
In a first attempt, we serialized the state at every command on the Entity.
When the API of my Entity grew, the serializations increased. It wasn’t a performance issue yet, but it also wasn’t one of the pieces of code to be proud of.
So we started brainstorming and came to the following solution.

We created the following interface:

public interface ICanBeOutOfSync
{
    void SyncMe();
}

All state objects with serialized state implement this interface.

Now we need to implement this method on our state objects. We do not want a reference from a state object to the entity so we provided a method on the state object in which the entity can provide an Action to Sync the state:

public class MyEntityState : ICanBeOutOfSync
{
    public void SyncMe()
    {
        _syncMethod();
    }

    private Action _syncMethod;
    public void RegisterSyncMethod(Action syncMethod)
    {
        _syncMethod = syncMethod;
    }
}

Now that we can call SyncMe() on the state object, we want to force that this method is called before SaveChanges() is called on the DbContext.

public class MyDataContext : DbContext
{
    public override int SaveChanges()
    {
        SyncEntitiesWhoCanBeOutOfSync();
    
        base.SaveChanges();
    }

    private void SyncEntitiesWhoCanBeOutOfSync()
    {
        var syncableEntities = ChangeTracker.Entries().Where(e => e.Entity.GetType().GetInterfaces().Any(x => x == typeof(ICanBeOutOfSync)));

        foreach (var syncableEntity in syncableEntities)
        {
            ((ICanBeOutOfSync)syncableEntity.Entity).SyncToMe();
        }
    }
}

The SaveChanges() of the DbContext is overridden and we make sure all Entities are synced.
We ask the ChangeTracker for all ICanBeOutOfSync Entities and call SyncMe() on all Entities to make sure they update their serialized data. When the serialized data is changed, the ChangeTracker will set the state to Modified.
When syncing is completed, we can call the SaveChanges() of the DbContext and let EntityFramework do its work.