Entity Framework Core Configuration
This document covers the various ways you can configure Entity Framework Core (EF Core) to suit your application's needs. Proper configuration is crucial for performance, security, and maintainability.
Connection Strings
The connection string tells EF Core how to connect to your database. It typically includes the server name, database name, authentication details, and other relevant parameters.
ASP.NET Core Configuration
In ASP.NET Core applications, connection strings are commonly stored in the appsettings.json
file and accessed via the configuration system.
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=MyDatabase;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}
You can then inject IConfiguration
into your DbContext
constructor to retrieve the connection string.
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
// ... DbSets
}
// In Startup.cs (or Program.cs for .NET 6+)
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
Other Application Types
For non-web applications, you can also store connection strings in configuration files or directly in code (though the former is generally preferred).
Options Configuration
EF Core provides extensive options for configuring its behavior. These are typically set when configuring your DbContext
.
DbContextOptionsBuilder
The DbContextOptionsBuilder
class allows you to set various options:
- Database Provider: Specifies which database provider to use (e.g., SQL Server, PostgreSQL, SQLite).
- Connection: Configures the database connection.
- Interceptors: Allows you to intercept database operations.
- Logging: Configures logging for EF Core operations.
- Query Splitting Behavior: Controls how queries are split into multiple SQL statements.
- Change Tracking Behavior: Defines how EF Core tracks changes to entities.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer("Server=myServer;Database=myDatabase;Trusted_Connection=True;")
.EnableSensitiveDataLogging() // For development
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); // Example: disable change tracking
}
}
EnableSensitiveDataLogging()
should only be used during development as it can expose sensitive data in logs.
Conventions
Conventions are a set of rules EF Core uses to infer model mappings from your entity types and properties without explicit configuration. You can customize or extend these conventions.
Default Conventions
EF Core has many built-in conventions, such as:
- Properties named
Id
orClassNameId
are treated as primary keys. - Properties with names like
NavigationPropertyName
followed by a primary key property are treated as foreign keys. - Public properties with backing fields are mapped by default.
Custom Conventions
You can create custom conventions to enforce specific naming patterns, data types, or other model aspects.
public class MyConvention : IModelFinalizingConvention
{
public void Apply(IConventionModelBuilder modelBuilder)
{
// Example: Ensure all string properties are NVARCHAR(200)
foreach (var property in modelBuilder.Metadata.GetProperties())
{
if (property.ClrType == typeof(string))
{
property.SetMaxLength(200);
}
}
}
}
// In DbContext.OnModelCreating
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder.Conventions.Add(<MyConvention>);
}
Fluent API
The Fluent API provides a programmatic way to configure your EF Core model. It's generally preferred over Data Annotations for complex configurations as it keeps mapping logic separate from your entity classes.
Configuring in OnModelCreating
The OnModelCreating
method in your DbContext
is where you typically use the Fluent API.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>().HasKey(p => p.ProductId); // Configure primary key
modelBuilder.Entity<Product>()
.Property(p => p.Name)
.IsRequired() // Make Name non-nullable
.HasMaxLength(100); // Set max length
modelBuilder.Entity<Category>()
.HasMany(c => c.Products) // Configure one-to-many relationship
.WithOne(p => p.Category)
.HasForeignKey(p => p.CategoryId);
modelBuilder.Entity<Order>()
.ToTable("Orders") // Map to a specific table name
.HasIndex(o => o.OrderDate); // Add an index
// Configure relationships with shared primary keys
modelBuilder.Entity<Blog>().HasMany(b => b.Posts).WithOne(p => p.Blog).HasForeignKey(p => p.BlogId);
modelBuilder.Entity<Post>().HasOne(p => p.Blog).WithMany(b => b.Posts).HasForeignKey(p => p.BlogId);
}
Data Annotations
Data Annotations are attributes you can apply directly to your entity classes to define their mapping and constraints. They are simpler for basic configurations.
Common Data Annotations
[Key]
: Designates a property as the primary key.[Required]
: Specifies that a property cannot be null.[StringLength(maxLength)]
: Sets the maximum length for string properties.[Column(name)]
: Specifies the column name.[Table(name)]
: Specifies the table name.[ForeignKey(name)]
: Configures foreign key relationships.[InverseProperty(name)]
: Specifies the navigation property on the other side of a relationship.
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
public class Product
{
[Key]
public int ProductId { get; set; }
[Required]
[StringLength(100)]
public string Name { get; set; }
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
public int CategoryId { get; set; }
[ForeignKey("CategoryId")]
public virtual Category Category { get; set; }
}
[Table("ProductCategories")]
public class Category
{
[Key]
public int CategoryId { get; set; }
public string Description { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
Understanding these configuration methods allows you to tailor EF Core's behavior to your specific database schema and application requirements.