January 2017
Volume 32 Number 1
[Data Points]
EF Core 1.1: A Few of My Favorite Things
By Julie Lerman
As I’m writing this column (in November 2016), Entity Framework (EF) Core 1.1 was just released. Between the 1.0 release and 1.1, a few significant things happened. In particular, the 1.0.1 patch fixed some critical bugs that were discovered just as 1.0 was being released. For a detailed list of those fixes, you can read the release notes at bit.ly/2fl5xNE. While most of these fixes relate to how LINQ queries are transformed to SQL, there are also fixes to the model builder, persistence via SaveChanges and migrations.
EF Core 1.1 brings additional bug fixes, many more improvements to how LINQ queries are interpreted, and big performance gains. But there are also new features—some that existed in EF6 but hadn’t made it to EF Core 1.0, keeping many developers from even looking at EF Core—and others that are completely new. What I want to do in this article is present a quick list of these changes and then highlight some that are of great interest to me. I’ll also provide links to the many valuable resources I use in my effort to keep up with EF Core as it evolves. To begin with, plenty of this information is covered in the docs (docs.microsoft.com/ef) and in the team blog posts (bit.ly/2ehZBUB).
In particular, you should be aware of Arthur Vickers’ blog. Arthur is a senior dev who has been on the team since the inception of POCO support in EF and has been instrumental in the modernization of EF. He has a great series of posts on EF Core 1.1 at blog.oneunicorn.com.
Microsoft plans to bring many EF6 features to EF Core, but not all of them. And there are a number of new features planned that will come in future versions. Right now, EF Core 1.1 focuses on upgrades that would make EF Core more satisfactory to a greater number of developers. Here are the most important of these features.
EF6 Features Now in EF 1.1
The DbSet.Find method, which became available with the introduction of the DbContext API in EF 4.1, didn’t make it onto the hit list for the first iteration of EF Core, upsetting a lot of developers. Find is more than a convenient way to efficiently query for an entity based on its key value. It first checks to see if that entity is already in memory and is being tracked by EF. If the entity can’t be found in the DbContext cache, EF executes a FirstOrDefault query on the database to retrieve the entity. This used to be a SingleOrDefault query in EF6 and earlier. Find’s design to avoid an unnecessary trip to the database is also a performance benefit. If you’re like me and want to see the plumbing, you can find the code in the EntityFinder class on GitHub (bit.ly/2e9V0Uu).
The other big difference is that Find is now in an EntityFinder service; it’s not just a method implemented directly in an internal DbSet class as it was in EF6. EF Core is made up of hundreds of services to encapsulate particular tasks. In his demos in the Channel 9 video on EF Core 1.1 (bit.ly/2fHOCsN), Rowan Miller shows how to use services directly, as well as how to replace them.
Also becoming part of EF Core with the 1.1 update is the EF6 feature referred to as connection resiliency, which provides support for easily handling transient connection problems that can happen when working against a remote database such as Azure SQL Database. The EnableRetryOnFailure extension method of the SQL Database provider can be set in DbContext.OnConfiguring or the AddDbcontext call in Startup.cs if you’re using ASP.NET Core dependency injection. EnableRetryOnFailure calls SqlServerRetryingExecutionStrategy, which inherits from the ExecutionStrategy type. You can create and set your own ExcecutionStrategy and other providers can predefine their own ExecutionStrategy configurations, as well. If you’re not familiar with this feature, it’s similar to the EF6 DbExecutionStrategy, which I covered in depth in my Pluralsight course, “EF6 Ninja Edition” (bit.ly/PS_EF6).
EF has always provided three ways of loading related data. One, eager loading, is enabled by the DbSet.Include method to retrieve graphs of data in a single query. Two others, in contrast, load related data after the main objects are already in memory and while the DbContext that’s tracking them is still in scope. Lazy loading automatically pulls in related data on-demand, while with explicit loading you explicitly tell EF to load the related data. Include was the first of these to be implemented in EF Core and became available with EF Core 1.0. It even has some nice improvements over versions from EF6 and earlier. Explicit loading with the Load method has now been added into EF Core 1.1. Lazy loading is not yet supported but will be at some point.
DbContext’s change tracker APIs let you access change tracker information directly, for example getting or setting the state of an entity with the DbContext.Entry(someObject).State method. EF6 brought additional control with new methods like GetDatabaseValues, CurrentValues and OriginalValues. These methods are now available in EF Core 1.1.
New Capabilities in EF 1.1
EF Core is filled with features that never existed in earlier versions. Here’s a short list of examples: batching during SaveChanges, unique foreign keys, the wonderful InMemory provider for testing, smarter LINQ query processing, and smarter and simpler fluent mappings.
EF 1.1 brings some additional new features and there’s one in particular that, as someone who’s a big fan of Domain-Driven Design (DDD), I’m quite fond of—support for encapsulated collections.
Mapped Fields and Encapsulated Collections EF Code First has only ever supported mapping to properties that have both a getter and a setter, even if the setter is private. And for collection navigations, the property was required to be an ICollection. If you want to constrain how the values of properties are populated, the ability to encapsulate the property is crucial—that way you can force anyone using your class to use a public method to ensure that the business rules around that property are honored. EF6 and earlier allow you to encapsulate scalar properties by making the setter private. But there’s no way to truly encapsulate collections and prevent anyone from modifying the collection directly.
With EF 1.1, you gain the ability to map directly to fields, as well as to map to IEnumerable properties. The new ability to map to fields, not just properties, allows you to use a more direct approach than hiding the setter and it also supports some additional ways of encapsulating scalar values. Here’s a property, DueDate, that has a getter but no setter, along with the field, _dueDate, which is tied to the property:
private DateTime _dueDate;
public DateTime DueDate {
get { return _dueDate;
}
}
The only way to set the DueDate is by calling the CalculateDueDate method, which modifies the field:
private void CalculateDueDate() {
_dueDate=Start.AddDays(DaysLoaned);
}
EF Core 1.1 requires an explicit mapping in the DbContext to inform EF that it can use the _dueDate field to map to the database, for example when returning the results of a query. You must use the Property (and optionally HasField) API methods to specify that the _dueDate field is a stand-in for the DueDate property. In this case, because the field name, _dueDate, follows an EF convention, I don’t have to use the HasField method, but I’ve added it in so you can see it:
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity<BookLoan>().Property(bl => bl.DueDate)
.HasField(“_dueDate”);
}
While you could use private setters before the field mapping was available, there was no way to encapsulate collections, to prevent anyone from directly manipulating a collection via its Add or Remove methods. It isn’t a matter of hiding the setter; what’s needed is to hide the collection methods. A common approach in DDD is to make the property an IEnumerable. However, with EF6 and earlier, you can only map to a flavor of an ICollection; but IEnumerable isn’t an ICollection.
At first I looked to see if you could use the field-mapping capability, but with EF 1.1 that isn’t possible as it only supports mapping to scalar properties. This is targeted to change in the next release of EF Core, which will allow mapping to navigation properties. But when I pointed this out one day on Twitter, Arthur Vickers let me know that in fact you can map to IEnumerables—something I’d somehow missed about EF Core. So I’m now able to encapsulate and protect a collection completely, forcing users of my API to go through a method to modify the collection. Here’s an example where I can add new BookLoan instances to a book every time it’s loaned, ensuring that the period of the loan is included:
private List<BookLoan> _bookLoans;
public IEnumerable<BookLoan> BookLoans {
get { return _bookLoans; }
}
public void BookWasLoaned(int daysLoaned){
_bookLoans.Add(new BookLoan(DateTime.Today, 14));
}
This is one pattern for achieving encapsulation by leveraging the IEnumerable mapping. But I recommend you read Arthur’s blog post (bit.ly/2fVzIfN) for more details, including how to do this without a backing field (a la my _bookLoans field), plans for enhancements and some gotchas to watch out for.
Support for Database-Specific Features EF Core is designed to allow providers to more easily support specific features of the data store. One example is that the SQL Server provider for EF Core supports SQL Server Memory-Optimized Tables for applications where you have incredibly high throughput. To specify that an entity maps to this special type of table, the SQL Server provider has an extension method you can use when configuring your model with the Fluent API:
modelBuilder.Entity<Book>().ForSqlServerIsMemoryOptimized();
Not only will this affect how code first generates table creation script, but it will also affect how EF generates commands to push data into the database. You can see an interesting demo of this in the previously mentioned Channel 9 video where Rowan Miller demos EF 1.1 features.
Shay Rojansky, who built the PostgreSQL provider for EF Core, wrote an article about how EF Core allowed him to support special features of PosgreSQL such as array types. Read it at bit.ly/2focZKQ.
Easier Access to Services
As I highlighted earlier with the EntityFinder service, EF Core is made up of hundreds of services. In the Channel 9 video, Rowan demonstrates how to access and use these services directly in your code. In addition, you can override a service with your own customization. EF 1.1 makes it easier to do that with a simple replace method that can be used in OnConfiguring. You can replace a service with another that either inherits from that service or implements the same interface. There’s no particular list of services—these are just classes throughout the various APIs of EntityFrameworkCore. A simple-to-grasp example is to create a class that inherits from a database type mapper, such as SqlLiteTypeMapper from the Sqlite provider, and add in a new type-mapping rule. Be sure that rule is one the database is able to cast. (Some cleverer type conversions will be coming in a future version of EF Core.) Then, in OnConfiguring, set up the replacement rule:
optionsBuilder.ReplaceService<SqliteTypeMapper,MySqliteTypeMapper>();
Why did I not replace the EntityFinder service? First, because I like the way it works. But second, because it’s a generic class, which makes creating a new version of it more complicated and I chose to set that chore aside for the time being. While ReplaceService was created to make it easier to replace internal services, you do need to keep in mind that EF Core internals could change and, therefore, your replacement might be problematic down the road. You can identify these easily enough because they’re in namespaces that end with the word Internal. From Microsoft: “We generally avoid breaking changes in non .Internal namespaces in minor and patch releases.”
Worth highlighting (because it caused a bit of a stir at the time) is a fix to a performance problem related to asynchronous queries that used the Include method, which was discovered just as 1.0 was about to be released. It was addressed quickly (see bit.ly/2faItD1 if you’re interested in the details) with a reported 70 percent increase in performance and is also part of the 1.1 release.
Wrapping Up
EF Core has a lot of sophisticated features. It’s incredibly important to be aware of what’s in, what’s not in, what’s coming and what’s never going to be part of EF Core. The EF Core documentation about its relationship to EF6 (bit.ly/2fxbVVj) is a useful resource, as well. The point is, you decide when EF Core is right for you and for your apps.
For most of the work I do, EF Core 1.1 has the APIs and features I need. As a DDD practitioner, the ability to encapsulate collections is a winner for me, though I’m still waiting for the complex type mappings to be included so I can also use value objects in my models. This feature is slated for the next release of EF Core. I was also excited to recently discover that EF Core has fulfilled a wish of mine—to define a read-only (non-tracking) DbContext. I had completely missed that this was added early on and was part of the 1.0 release of EF Core. You can read more about that in my blog post at bit.ly/2f75l8m.
Julie Lerman is a Microsoft MVP, .NET mentor and consultant who lives in the hills of Vermont. You can find her presenting on data access and other .NET topics at user groups and conferences around the world. She blogs at thedatafarm.com/blog and is the author of “Programming Entity Framework,” as well as a Code First and a DbContext edition, all from O’Reilly Media. Follow her on Twitter: @julielerman and see her Pluralsight courses at juliel.me/PS-Videos.
Thanks to the following Microsoft technical expert for reviewing this article: Rowan Miller