Implementing Missing Features in Entity Framework Core – Part 7: Entity Configuration in Mapping Classes

This is the seventh post in a series of posts about bringing the features that were present in Entity Framework pre-Core into EF Core. The others are:

  • Part 1: Introduction, Find, Getting an Entity’s Id Programmatically, Reload, Local, Evict

  • Part 2: Explicit Loading

  • Part 3: Validations

  • Part 4: Conventions

  • Part 5: Getting the SQL for a Query

  • Part 6: Lazy Loading

This time I’m going to cover automatic entity configuration in mapping classes, that is, outside of the DbContext.OnModelCreating method. If you remember, Entity Framework Code First supported having classes inheriting from EntityTypeConfiguration in the same assembly as the context, and these classes would be loaded automatically. This made it much simpler to add new mapping classes to a project without touching the context.

This functionality hasn’t been ported to Entity Framework Core yet, but it is being developed for the next version, and is tracked by ticket 2805. My implementation finds mapping classes in the same assembly as the context automatically, or it can load configuration explicitly from a mapping class. Here is my contract for the mapping class:

public interface IEntityTypeConfiguration<T> where T : class
{
void Configure(EntityTypeBuilder<T> entityTypeBuilder);
}

As you can see, this needs to be implemented in a concrete generic class and bound to a specific entity type.

The actual implementation goes like this:

public static class EntityTypeConfigurationExtensions
{
private static readonly MethodInfo entityMethod = typeof(ModelBuilder).GetTypeInfo().GetMethods().Single(x => (x.Name == "Entity") && (x.IsGenericMethod == true) && (x.GetParameters().Length == 0));

private static Type FindEntityType(Type type)
{
var interfaceType = type.GetInterfaces().First(x => (x.GetTypeInfo().IsGenericType == true) && (x.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>)));
return interfaceType.GetGenericArguments().First();
}

private static readonly Dictionary<Assembly, IEnumerable<Type>> typesPerAssembly = new Dictionary<Assembly, IEnumerable<Type>>();

public static ModelBuilder ApplyConfiguration<T>(this ModelBuilder modelBuilder, IEntityTypeConfiguration<T> configuration) where T : class
{
var entityType = FindEntityType(configuration.GetType());

dynamic entityTypeBuilder = entityMethod
.MakeGenericMethod(entityType)
.Invoke(modelBuilder, new object[0]);

configuration.Configure(entityTypeBuilder);

return modelBuilder;
}

public static ModelBuilder UseEntityTypeConfiguration(this ModelBuilder modelBuilder)
{
IEnumerable<Type> configurationTypes;
var asm = Assembly.GetEntryAssembly();

if (typesPerAssembly.TryGetValue(asm, out configurationTypes) == false)
{
typesPerAssembly[asm] = configurationTypes = asm
.GetExportedTypes()
.Where(x => (x.GetTypeInfo().IsClass == true) && (x.GetTypeInfo().IsAbstract == false) && (x.GetInterfaces().Any(y => (y.GetTypeInfo().IsGenericType == true) && (y.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>)))));
}

var configurations = configurationTypes.Select(x => Activator.CreateInstance(x));

foreach (dynamic configuration in configurations)
{
ApplyConfiguration(modelBuilder, configuration);
}

return modelBuilder;
}
}

You can see that it uses some dynamic magic to make things simpler, otherwise we’d need to have even more reflection. Dynamics take care of these things quite nicely.

The code essentially looks at the entry assembly and finds all non-abstract public types that implement IEntityTypeConfiguration<T>. For each of those, it creates an instance, extracts the template argument and creates an EntityTypeBuilder<T> from calling the Entity<T> method of the ModelBuilder class and calls the IEntityTypeConfiguration<T>.Configure method of the instantiated mapping class passing it the EntityTypeBuilder<T> which allows it to supply mapping configuration for the mapped entity (T).

We need to explicitly call this extension inside DbContext.OnModelCreating:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.UseEntityTypeConfiguration();
base.OnModelCreating(modelBuilder);
}

And it takes care of everything for us. Or, if we want to load a single mapping class explicitly, we can also do so:

modelBuilder.UseEntityTypeConfiguration<MyEntityTypeConfiguration>();

Finally, a simple mapping class might be:

public class MyEntityTypeConfiguration : IEntityTypeConfiguration<MyEntity>
{
public void Configure(EntityTypeBuilder<MyEntity> entityTypeBuilder)
{
entityTypeBuilder.ToTable("MyEntity");
entityTypeBuilder.Property(x => x.MyEntityId).HasColumnName("Id");
}
}

In case you’re interested, this feature is similar to the one being implemented for .NET Core, except that it doesn’t find mapping classes automatically. The IEntityTypeConfiguration<T> interface is exactly the same.

Technologies to Follow in 2017

Introduction

A lot is happening and it’s difficult to keep track of everything. Based on my work and on what I see over the Internet, I decided to write a post about the technologies – tools, languages, servers, operating systems, etc – that I find more interesting and promising. I know, some of these will be controversial, others are not exactly new, I am even mixing totally different things together, but, hey, it’s my opinion – feel free to share your objections here! Winking smile

I am not going to cover the myriad of JavaScript frameworks, because they’re just too many. I will only talk about what I know. For that same reason, I’m not talking about Akka, Go, Scala, Python, Ruby, Erlang, etc, because, honestly, I never used them. Also, I don’t cover Java, although Kafka is written in Java, because I haven’t used Java in anger for more than 10 years. I read that it’s having some problems, with some key people leaving Oracle, persisting security problems and the delaying of releases, but I’m sure Java is here to stay. Others will be more fit to talk about it.

.NET Core

.NET Core is Microsoft’s next version .NET framework, only this time totally modular, open source and multi-platform. Runs on Linux and MacOS, not just Windows. Still doesn’t have all the features of classic .NET, but it will get there: next version (2.0) will more than double the supported APIs. Right now, it’s perfect for writing .NET MVC apps and web APIs that need to run in other operating systems, including inside Docker containers. Get it from https://github.com/dotnet/core.

Node.js

A JavaScript runtime for the desktop instead of the browser. Uses an event-driven, asynchronous I/O model for high performance and scalability. Has probably the largest ecosystem of open source libraries in the world – NPM. Free and open source, with new features continuously being released. Currently uses Google’s V8 engine, but Microsoft submitted a patch to allow it to run Chakra, it’s JavaScript engine! Exciting times! Its site is https://nodejs.org.

Docker

You favorite container technology! Now supported in both Amazon Web Services and Azure, and with native support in Windows Server 2016. This is a must have for highly scalable applications. Free but it’s possible to get a paid repository online. A lot going on around it, the only problem is that things tend to change in non-retro-compatible ways, still need maturing. See more at http://docker.com.

Elasticsearch

A distributed and open source search engine based on Lucene. A blazing fast NoSQL database with replication capabilities, it is the most widely known component of the ELK stack, together with Kibana (for reporting and visualizations), Logstash (for data import) and Beats (for data shipping). Even Azure Search uses it behind the covers. Free but some tools are paid. Get it from http://elastic.co.

ECMAScript 2015

The next generation JavaScript, also known as ECMAScript 6. Heavily influenced by TypeScript, it offers a number of features from compiled languages, such as lambda functions, classes, type safety, etc. Before it’s available everywhere, people are using Babel.js to compile it to classic JavaScript. Google Chrome’s V8 engine already supports a great deal of it, as does Firefox. The specification is available here: http://www.ecma-international.org/ecma-262/6.0/.

HTML5

Is there any other, I hear you ask? Well, except if you need to support that old two-letter browser who had an infamous version 8, not really. Together with HTML 5 came a wealth of APIs that now allow us to have near-desktop quality apps on the web, and in some mobile browsers too. Latest standard is 5 but 5.1 is due to come out this year. Interestingly, HTML5 is more and more not just about web applications but also being used for desktop ones: for example, the Spotify desktop client is an HTML5 app. The specification is available at https://www.w3.org/TR/html5.

Kafka

A high throughput, low-latency open source message broker from the Apache foundation. Can stream data in real-time for massive simultaneous clients and has bindings for several languages. Similar to a distributed transaction log with exactly once semantics. More info here: https://kafka.apache.org.

TypeScript

A superset of JavaScript offering type safety and class-based object-oriented features. Nice wrappers around promises using similar syntax to C#’s async/await. It is compiled to JavaScript, so it can run anywhere JavaScript can. Free license. The official site is https://www.typescriptlang.org.

MongoDB

An open source NoSQL document database designed for high performance and with interesting clustering features. Mappings for all common languages, including scripting ones. With it you get JSON storage, indexes and automatic expiration. With free and commercial licenses. See more at http://www.mongodb.com.

Git

A free and open source distributed source control from the author of Linux. Now being used everywhere, even Microsoft is using it instead of their own TFS. Not an easy beast to master, I may add. Also worth mentioning GitFlow, a proposed workflow for branching and release management. The official site is https://git-scm.com.

Nginx

A high performance web server, HTTP cache and reverse proxy server for several TCP protocols. Can serve .NET and any other language, probably best used as a reverse proxy, particularly in the case of .NET Core. Runs on Windows and several UNIX flavors. It is free to use. Available from https://www.nginx.com.

Octopus Deploy

An automated deployment and release management tool for .NET applications. Latest versions can deploy both web apps as well as Windows services. Plays nicely with Continuous Integration and build tools such as Jenkins and TeamCity. Both free and commercial licenses. The web site is https://octopus.com.

Azure

Microsoft’s Cloud offering, the competitor of Amazon Web Services. Loaded with powerful services and features, which include amazing machine learning services, containerization as a service, queuing, and anything that can be expected from a Cloud service. Possible to get a time-limited trial for free. The official site is https://azure.microsoft.com.

Amazon Web Services

One of the two major players in the Cloud market, the other being Azure. Still has the biggest market share and offers a number of interesting features. Leaning slightly more towards Java and JavaScript than to .NET. Anyone can get a free account, as long as a credit card is supplied. See more at https://aws.amazon.com.

Linux

The free and open source operating system that just a few years ago Microsoft compared to a virus! Based on UNIX, now not just for geeks, it is everywhere, especially with the arriving of Docker. Several distributions available, to match anyone’s preferences, some free and some commercial. Windows 10 now even runs bash natively! See more at https://kernel.org.

Visual Studio Code

A powerful and extensible yet lightweight IDE from Microsoft based on GitHub’s Electron, which can run in a number of platforms, from Windows and Linux to MacOS. Includes support for a number of languages, Git integration, debugging capabilities – which make it stand from others such as Sublime or Atom – and an extension mechanism. Hey, it’s free! Get it from http://code.visualstudio.com.

Xamarin

A cross-platform implementation of .NET, for Windows Phone, Android and iOS. Before .NET Core came along – in fact, even after that – it is the preferred tool for creating applications that need to target multiple platforms. Now offered for free by Microsoft. but the Enterprise version will require a Visual Studio paid license. Microsoft promised to make it open source. Official site is https://www.xamarin.com.

Google Analytics

A web analytics service offered for free by Google, although paid subscriptions also exist. Can be used to track not only traffic but also custom events, and also in mobile apps. It’s unbelievable the amount of information that one can get out of it. See it in https://analytics.google.com.

SQL Server 2016

In-memory tables, JSON support, Query Store, integrated R, row and column-level security, etc, make this one of the most interesting versions of SQL Server ever. Available for free with limitations as Express edition, and as a paid license. More info from http://microsoft.com/sqlserver.

Let’s Encrypt

Free SSL certificates for the masses! No need to pay for a certificate, now you can get any number for free. Easily installable in any server (even IIS), but expires every 90 days. Get yours from https://letsencrypt.org.

TensorFlow

TensorFlow is Google’s second generation open source library for machine intelligence. It uses data flow graphs to represent mathematical operations and is the core of several Google products, such as Gmail, Google Photos and others. It offers Python and C++ bindings and recently it compiles on Windows as well as Linux and Mac OSX. Get it from https://github.com/tensorflow/tensorflow.

GitLab

GitLab is a free (with an enterprise license too) repository manager built on Git. It is fast moving with a plethora of very useful features. You can install it on premises or run it in the cloud. Offers integration with LDAP servers for authentication, offers a pretty decent Continuous Integration feature, plus a lot of other cool stuff. Check it out at https://about.gitlab.com.

Redis

A distributed cache with open source implementations in Linux and Windows. Currently, probably the most used one. Offered by both Azure and AWS. Not just BLOB cache, offers interesting structures. Learn about it at https://redis.io.

Conclusion

So, what are your thoughts – am I missing something? Do you agree or disagree with my choices? I’d love to hear from you!

Fusion Tech Talk #1

(Portuguese only, sorry!)

IMG_20170207_184521

Na passada terça-feira, 7, teve lugar nas instalações da Fusion Cowork o primeiro evento Fusion Tech Talk!

Tive a honra de fazer uma apresentação sobre a Microsoft e o open-source e a segunda apresentação, sobre Cake, foi feita pelo Pedro Marques (@pitermarx).

Tivemos uma boa afluência, cerca de 40 pessoas, o que, para um primeiro evento, não foi nada mau! Outro se seguirão, para tal, convido-vos a submeter ideias em https://www.meetup.com/Aveiro-Technology-Talk.

Obrigado ao Pedro Marques, à Fusion Cowork e a todos os que estiveram presentes, conto ver-vos nos próximos eventos! Winking smile