« Entity Framework Core 8 » : différence entre les versions
Apparence
Page créée avec « Category:.NET Core = Links = * [https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-8.0/whatsnew What's New in EF Core 8.0] * Entity Framework Plus * [https://linq2db.github.io/index.html linq2db] = Entity Framework Core Tools = == [https://docs.microsoft.com/en-us/ef/core/miscellaneous/cli/dotnet .NET Core CLI] == <kode lang='powershell'> # test if Entity Framework Core Tools has been installed dotnet ef # be sure to run... » |
Aucun résumé des modifications |
||
(6 versions intermédiaires par le même utilisateur non affichées) | |||
Ligne 1 : | Ligne 1 : | ||
[[Category:.NET | [[Category:.NET]] | ||
= Links = | = Links = | ||
* [https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-8.0/whatsnew What's New in EF Core 8.0] | * [https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-8.0/whatsnew What's New in EF Core 8.0] | ||
* [[Entity_Framework_Plus|Entity Framework Plus]] | * [[Entity_Framework_Plus|Entity Framework Plus]] | ||
* [https://linq2db.github.io/index.html linq2db] | * [https://linq2db.github.io/index.html linq2db] | ||
* [[Repository_Pattern|Repository Pattern]] | |||
= Entity Framework Core Tools = | = Entity Framework Core Tools = | ||
Ligne 162 : | Ligne 163 : | ||
<kode lang='ps'> | <kode lang='ps'> | ||
# SQL Server | |||
Scaffold-DbContext 'Data Source=MY-PC;Initial Catalog=MyDb' Microsoft.EntityFrameworkCore.SqlServer -OutputDir Entities | Scaffold-DbContext 'Data Source=MY-PC;Initial Catalog=MyDb' Microsoft.EntityFrameworkCore.SqlServer -OutputDir Entities | ||
# MariaDB | |||
Scaffold-DbContext 'ConnectionStrings:MyConnectionString' Pomelo.EntityFrameworkCore.MySql -OutputDir DataAccess/Entities -ContextDir DataAccess -Context "BourseContext" -Force | |||
</kode> | </kode> | ||
Ligne 175 : | Ligne 180 : | ||
== [https://learn.microsoft.com/en-us/ef/core/managing-schemas/scaffolding/templates?tabs=dotnet-core-cli Custom Reverse Engineering Templates] == | == [https://learn.microsoft.com/en-us/ef/core/managing-schemas/scaffolding/templates?tabs=dotnet-core-cli Custom Reverse Engineering Templates] == | ||
= [https://www.devtrends.co.uk/blog/avoid-asnotracking-and-include-when-querying-using-entity-framework-in-asp.net Avoid using AsNoTracking and Include] = | = [https://www.devtrends.co.uk/blog/avoid-asnotracking-and-include-when-querying-using-entity-framework-in-asp.net Avoid using AsNoTracking and Include] = | ||
Ligne 423 : | Ligne 262 : | ||
return items; | return items; | ||
} | } | ||
</kode> | </kode> |
Dernière version du 6 avril 2025 à 17:31
Links
Entity Framework Core Tools
.NET Core CLI
# test if Entity Framework Core Tools has been installed
dotnet ef
# be sure to run the previous command in the folder of the project where EF has been added
# dotnet ef must be installed as a global or local tool
dotnet tool install --global dotnet-ef
# installed in ~/.dotnet/tools
# Add ~/.dotnet/tools to PATH
# update
dotnet tool update dotnet-ef --global
# --version 7.0.14
|
Package Manager Console in Visual Studio
![]() |
Visual Studio
|
# test if Entity Framework Core Tools has been installed
Get-Help about_EntityFrameworkCore
# install
Install-Package Microsoft.EntityFrameworkCore.Tools
# update
Update-Package Microsoft.EntityFrameworkCore.Tools
|
Add Entity Framework Core package
# sql server
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
# mysql
dotnet add package Pomelo.EntityFrameworkCore.MySql
|
![]() |
Microsoft.EntityFrameworkCore.Design allows to scaffold and has to be installed on the executed project. |
Data Providers
Provider | Package NuGet | Connection String |
---|---|---|
SQL Server | Microsoft.EntityFrameworkCore.SqlServer | Server=(localdb)\\MSSQLLocalDB;Database=MyDb;Integrated Security=True;MultipleActiveResultSets=True; Server=localhost;Database=MyDb;User=sa;Password=pwd; |
MySQL / MariaDB | Pomelo.EntityFrameworkCore.MySql | server=localhost;database=MyDb;user=root;password=pwd |
PostgreSQL | Npgsql.EntityFrameworkCore.PostgreSQL | Host=localhost;Database=MyDb;Username=root;Password=pwd |
InMemory | Microsoft.EntityFrameworkCore.InMemory | databaseName: "test_database" |
Sqlite | Microsoft.EntityFrameworkCore.Sqlite | Data Source=/tmp/file.db |
Connection string
- The connection string could be stored in the secret store in dev environnement
- It could also be stored in appsettings.Development.json in dev environnement
appsettings.json |
{
"ConnectionStrings": {
"MariaDb": "server=localhost;database=test;user=test;password=***"
}
}
|
Dependency injection (ASP.Net Core)
![]() |
By default the DbContext is registered as a scoped service: a new DbContext is created on a new thread for each API request. |
MariaDb / MySql
Program.cs |
var connectionString = builder.Configuration.GetConnectionString("MariaDb"); // get the connection string from the appsettings.json or the secret store
var serverVersion = new MariaDbServerVersion(new Version(10, 11, 4));
builder.Services.AddDbContext<MyAppContext>(
dbContextOptions => dbContextOptions
.UseMySql(connectionString, serverVersion));
|
SSL Authentication Error
On Windows, if named pipe authentication is used you may have this issue.
Disable SSL in the connection string to workaround it: sslmode=none
SQL Server
SqlConnectionStringBuilder
Program.cs |
var connectionStringWithoutPassword = builder.Configuration.GetConnectionString("SqlServer");
var connectionStringBuilder = new SqlConnectionStringBuilder(connectionStringWithoutPassword); // Package: System.Data.SqlClient
connectionStringBuilder.Password = builder.Configuration["SqlServerPassword"];
var connectionString = connectionStringBuilder.ConnectionString;
|
DbContext OnConfiguring
DataAccess/MyAppContext.cs |
public class MyAppContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("server=localhost;database=test;user=test;password=***"); // hard-coded connection string
optionsBuilder.UseMySql("name=ConnectionStrings:MariaDb", ServerVersion.Parse("10.11.4-mariadb")); // get it from the appsettings.json or the secret storage
optionsBuilder.UseSqlServer(ConfigurationManager.ConnectionStrings["SqlServerConnectionString"].ConnectionString); // WPF
|
Log underlying SQL query
Program.cs |
builder.Services.AddDbContext<AppContext>(
options => options
.LogTo(Console.WriteLine, LogLevel.Information) // simple logging
.UseLoggerFactory(LoggerFactory.Create(loggingBuilder =>
loggingBuilder
.AddConfiguration(builder.Configuration.GetSection("Logging")) // log the configuration
.AddConsole() // log into the console if there is one
.AddDebug())) // log into VS output Window and Linux journal
.EnableSensitiveDataLogging( // include the values of data in exception messages
builder.Configuration.GetValue<bool>("DbContextLogOptions:EnableSensitiveDataLogging", false))
.EnableDetailedErrors( // wrap each call to read a value in a try-catch block
builder.Configuration.GetValue<bool>("DbContextLogOptions:EnableDetailedErrors", false))
.UseMySql(connectionString, serverVersion)
);
|
appsettings.json |
"DbContextLogOptions": {
"EnableSensitiveDataLogging": true,
"EnableDetailedErrors": true
},
|
Database first: scaffold database to model entities
# generate entity classes and context class
dotnet ef dbcontext scaffold
"Server=localhost;Database=MyDb;User=sa;Password=***;" # an harcoded connection string
"Name=ConnectionStrings:SqlServer" # get the connection string from the appsettings.json or the secret storage
Microsoft.EntityFrameworkCore.SqlServer # the database provider
--output-dir DataAccess/Entities # output folder for entities
--context-dir DataAccess # output folder for DbContext
--context "MyDbContext" # default context name: DbNameContext
--force # overwrite all the class files
--table table1 --table table2 # scaffold only table1 and table2
|
Visual Studio
- Ensure Entity Framework Core Tools have been installed
- View → Other Windows → Package Manager Console
- Default Project = the one containing the entity configurations ?
- Startup Project = the one containing the sql server configuration ?
# SQL Server
Scaffold-DbContext 'Data Source=MY-PC;Initial Catalog=MyDb' Microsoft.EntityFrameworkCore.SqlServer -OutputDir Entities
# MariaDB
Scaffold-DbContext 'ConnectionStrings:MyConnectionString' Pomelo.EntityFrameworkCore.MySql -OutputDir DataAccess/Entities -ContextDir DataAccess -Context "BourseContext" -Force
|
Error | Titre colonne 2 |
---|---|
The certificate chain was issued by an authority that is not trusted | Add Encrypt=False to the connection string |
Login failed for user | Add Integrated Security=True to the connection string |
Custom Reverse Engineering Templates
Avoid using AsNoTracking and Include
AsNoTracking is used to improve performances when you don't need the entities to be tracked for changes. But a better way to improve performances is to use projection so you don't return the whole entity but only the needed fields. This way you don't need AsNoTracking because there is no more entities to track.
Include is used to retrieve other entities linked by a foreign key / navigation property. If you use a projection with a navigation property, you don't have to use Include.
Query generation
string contains vs like
context.Items.Where(x => x.Name.Contains("item1"));
|
SELECT [i].[Id], [i].[Name]
FROM [Items] AS [i]
WHERE (@__query_Name_0 LIKE N'') OR (CHARINDEX(@__query_Name_0, [i].[Name]) > 0)
|
context.Items.Where(x => EF.Functions.Like(x.Name, "%item1%"));
|
SELECT [i].[Id], [i].[Name]
FROM [Items] AS [i]
WHERE [i].[Name] LIKE @__Format_1
|
any
context.Items.Any(x => x.Id == 1);
|
SELECT EXISTS (
SELECT 1
FROM `item` AS `i`
WHERE `i`.`id` = @__id_0)
|
left join
// with navigation property
context.Users.Select(u => new { u.Name, u.Group?.Name });
// method syntax
context.Users
.GroupJoin(
context.Groups,
user => user.GroupId,
group => group.Id,
(user, grouping) => new { user, grouping }
)
.SelectMany(z => z.grouping.DefaultIfEmpty(), (z, grp) => new { userName = z.user.Name, groupName = grp.Name })
.Select(x => new { x.userName, x.groupName });
// query syntax
from user in context.Users
join group in context.Groups
on user.GroupId equals group.Id into grouping
from grp in grouping.DefaultIfEmpty()
select new { userName = user.Name, groupName = grp.Name };
|
SELECT u.Name AS userName, g.Name AS groupName
FROM User AS u
LEFT JOIN Group AS g
ON u.GroupId = g.Id
|
Pagination
public async Task<IReadOnlyCollection<Item>> GetItemsAsync(ItemQuery query, CancellationToken cancellationToken)
{
var items = await this.context.Items
.Skip((query.PageIndex - 1) * query.PageSize)
.Take(query.PageSize)
.AsNoTracking()
.ToListAsync(cancellationToken);
return items;
}
|