Introduction
Entity Framework Core is a lightweight and extensible version of Entity Framework. It is based on ORM (Object-Relational Mapper) which enables us to work with databases using .NET objects. This article explains the new features of EF Core 2.0. Following are the new features.
- Query
- Like query operator
- Improved LINQ Translation
- GroupJoin improvements
- String interpolation (using FromSql and ExecuteSqlCommand)
- Performance
- Explicitly compiled queries
- DbContext pooling
- Modeling
- Model-level query filters
- Database scalar function mapping
- Self-contained type configuration for code first
- Table splitting
- Owned types
Query
Like query operator
We can use EF.Functions.Like() with a LINQ query and it will be translated to LIKE in SQL; For example.
var data1 = from emp in context.Employees
where EF.Functions.Like(emp.Name, "j%")
select emp;
is translated to
SELECT [e].[Id], [e].[IsDeleted], [e].[Name]
FROM [Employee] AS [e]
WHERE ([e].[IsDeleted] = 0) AND [e].[Name] LIKE N'j%'
Improved LINQ Translation
There are many improvements in LINQ translation with more logic being evaluated in the database rather than in memory and less unnecessary data being retrieved from the database.
GroupJoin improvements
There is an improvement in SQL generation that has group joins.
String interpolation (using FromSql and ExecuteSqlCommand)
The C# 6.0 introduced a string interpolation feature that allows C# expressions to be embedded in string literals directly. Using two primary APIs, FromSql and ExecuteSqlCommand, special support for interpolation has been added.
string name = "Jignesh";
var data2 = context.Employees.FromSql($@"
SELECT *
FROM Employee
WHERE name = {name}");
Performance
Explicitly compiled queries
In the previous version of Entity Framework, explicitly compiled query APIs were provided and also allowed the application to cache the translation of queries so that they can be translated once and executed many times.
Entity Framework Core can automatically compile and cache the queries based on the hashed representation of the query expression. It can be used to obtain a little performance gain by bypassing the computation of the hash and cache lookup and allowing the application to use an already compiled query that is invoked by using a delegate.
Example
// Get All Employee
private static Func<EntityModelContext, IEnumerable<Employee>> _allEmployee =
EF.CompileQuery((EntityModelContext db) =>
db.Employees
);
// Get specific employee by using Id
private static Func<EntityModelContext, int, Employee> _getEmployeeById =
EF.CompileQuery((EntityModelContext db, int id) =>
db.Employees
.Where(p => p.Id == id).FirstOrDefault()
);
DbContext pooling
In ASP.NET Core applications, the EF Core dbcontext is registered as dependency injection. This instance can be obtained through the constructor of the Controller. This means that a new instance of context is created when the Controller is requested.
In EF 2.0, new ways to register dbcontext in DI are introduced that transparently introduce a pool of reusable DbContext instances. To use DbContext pooling, we have to use AddDbContextPool instead of AddDbContext in service registration.
services.AddDbContextPool<EmployeeContext>(
options => options.UseSqlServer(connectionString));
When the Controller requests a DbContext instance, it first checks if there is an instance available in the pool. Once the request is finalized, the state of the instance is reset and returned to the pool. It helps to save the cost of initialization of the DbContext instance.
This method has some limitations it cannot understand what can be done in the OnConfigure() method of the DbContext. It has been advised not to use this method if we maintain our own state in our derived DbContext class. It cannot be shared across requests. EF Core will only be able to reset the state that is aware of before adding a DbContext instance to the pool.
Modeling
Model-level query filters
This feature allows us to specify filters in the model level that are automatically applied to all queries executed on the DB context on the specified type. It means that Entity Framework automatically adds the filter in the WHERE clause before executing the queries. This feature can be used as common application features, such as soft delete and multi-tenancy.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Employee>().HasQueryFilter(p => !p.IsDeleted);
}
Following is the limitation of this feature.
- Navigation references are not allowed
- The filter can be defined only on root entity type
Database scalar function mapping
This feature enables mapping of database scalar functions to a method in the class. This method can be used with LINQ queries and translated into a SQL statement.
Example
public class EntityModelContext : DbContext
{
[DbFunction]
public static string GetEmployeeName(int id)
{
throw new Exception();
}
}
Self-contained type configuration for code first
In Entity Framework 6.0, it is possible to encapsulate the code-first configuration of a specific entity type by deriving from EntityTypeConfiguration. The same feature is now available with EF 2.0.
Example
public class EmployeeConfiguration : IEntityTypeConfiguration<Employee>
{
public void Configure(EntityTypeBuilder<Employee> builder)
{
builder.HasKey(c => c.AlternateKey);
builder.Property(c => c.Name).HasMaxLength(200);
}
}
public class EntityModelContext : DbContext
{
builder.ApplyConfiguration(new EmployeeConfiguration());
}
Table splitting
Older Entity Framework (EF 4 or above) allowed us to split one table into multiple entities. Now, this feature is available in EF Core 2.0. The main advantage of table splitting is that our entity model remains very simple and straightforward and contains only the logical related fields. It may help in improving the performance by selecting specific columns from the table. In table splitting, the primary columns will be shared.
Owned types
An owned entity type can share the same CLR type with another owned entity type, but this cannot be identified just by the type. There must be a navigation to it from another entity type. The owner contains the entity as a navigation. When the owner will query, the owned type will be included by default. It is very similar to complex type in EF 6.
Example
public class EntityModelContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Employee>().OwnsOne(p => p.EmployeeDetails, cb =>
{
cb.OwnsOne(c => c.HomeAddress);
cb.OwnsOne(c => c.OfficeAddress);
});
}
}
public class Employee
{
public int Id { get; set; }
public EmployeeDetails EmployeeDetails { get; set; }
}
public class EmployeeDetails
{
public Address HomeAddress { get; set; }
public Address OfficeAddress { get; set; }
}
public class Address
{
public string AddressLine1 { get; set; }
public string City { get; set; }
}
How to install EF Core 2.0
We can install Entity Framework Core 2.0 by using CLI or NuGet packages.
Using .NET Core CLI -
dotnet add package Microsoft.EntityFrameworkCore.SqlServer -V 2.0.0
Using NuGet Package Manager -
PM> Install-Package Microsoft.EntityFrameworkCore.SqlServer -Version 2.0.0
Summary
Entity Framework Core 2.0 comes with many new features and improvements in the existing features. This version of EF Core includes many features that are available with EF 6.