web-dev-qa-db-fra.com

Utilisation des migrations Entity Framework Core pour un projet de bibliothèque de classes

Cela semble être un problème qui a déjà été résolu , du moins pour les bases de données SQLite.

Ma solution consiste en 3 projets:

  1. Projet WPF (projet de démarrage par défaut) (.NET Framework 4.7),
  2. Projet "principal" contenant le modèle d'affichage et les éléments non liés à l'interface utilisateur - Projet de bibliothèque de classes (.NET Standard 2.0)
  3. Projet "relationnel" contenant la totalité de la couche de données Entity Framework - j'aime bien les séparer (.NET Standard 2.0)

J'ai installé les packages suivants dans le projet WPF principal:

Microsoft.EntityFrameworkCore.Tools
Microsoft.EntityFrameworkCore.Design

Les projets 2 et 3 sont référencés dans mon projet principal WPF. Donc, fondamentalement, cela devrait suffire à l'EF pour résoudre les DbContextes.

Cependant, ce n'est pas le cas - car l'exécution de Add-Migration sur mon projet WPF a pour résultat:

PM> Add-Migration "Initial"
No DbContext was found in Assembly 'TestWPFProject'. Ensure that you're using the correct Assembly and that the type is neither abstract nor generic.

Le passage au projet 3 par défaut dans la console du gestionnaire de packages a pour résultat:

PM> Add-Migration "Initial"
Unable to create an object of type 'ClientDbContext'. Add an implementation of 'IDesignTimeDbContextFactory<ClientDataStoreDbContext>' to the project, or see https://go.Microsoft.com/fwlink/?linkid=851728 for additional patterns supported at design time.

Comment utiliser correctement les migrations EF Core avec mon projet de bibliothèque de classes et mon projet WPF?

4
Lucas

J'ai reproduit votre solution et trouvé ... une solution :)

  1. Projet "Core" - appelé ClassLibrary1
  2. Projet "relationnel" - appelé EFClssLibrary
  3. Projet WPF App - appelé WpfApp1

Approfondissons.


1. Projet principal

Nom: ClassLibrary1.

Type: bibliothèque de classes .NET Standard 2.0.

Dépendances: aucune.

Dans ma solution de test, il ne contient qu'une seule classe, un modèle appelé Person.

Person.cs

namespace ClassLibrary1
{
    public class Person
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Surname { get; set; }
    }
}

2. Projet relationnel

Nom: EFClassLibrary.

Type: bibliothèque de classes .NET Standard 2.0.

Dépendances

Ce projet, dans ma solution de test, contient une seule classe: le contexte de la base de données.

ClientDbContext.cs

using ClassLibrary1;
using Microsoft.EntityFrameworkCore;

namespace EFClassLibrary
{
    public class ClientDbContext : DbContext
    {
        const string connectionString = "Server=(localdb)\\mssqllocaldb;Database=ClientDb;Trusted_Connection=True;";

        public ClientDbContext() : base() { }

        public ClientDbContext(DbContextOptions<ClientDbContext> options) : base(options) { }

        public DbSet<Person> People { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(connectionString);
        }
    }
}

Chaîne de connexion

Dans cette classe, a défini et utilisé la chaîne de connexion pour se connecter à la base de données (en supposant que c'est LocalDb SQL Server). Si vous souhaitez placer la chaîne de connexion dans un fichier de configuration, vous pouvez ajouter un fichier de configuration partagé à votre solution, puis référencer ce fichier dans votre fichier App.config (pour plus d'informations, consultez cette page )

Configuration du framework cible

Pour pouvoir ajouter des migrations sur ce projet sans définir d'autres projets comme projet de démarrage, vous devez définir le cadre cible. Faites un clic droit sur le projet et cliquez sur l'entrée Edit EFClassLibrary.csproj. Au-dessous de la ligne <TargetFramework>netstandard2.0</TargetFramework>, vous devez ajouter une autre ligne indiquant le cadre que vous souhaitez cibler. Pour cibler le .NET Framework 4.7, vous devez ajouter 

<TargetFramework>net47</TargetFramework>

Vous trouverez une liste de toutes les valeurs autorisées ici .

Mon EFClassLibrary.csproj ressemble au code ci-dessous après avoir ajouté le .NET Framework 4.7 comme cible.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <TargetFramework>net47</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.1.1" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\ClassLibrary1\ClassLibrary1.csproj" />
  </ItemGroup>

</Project>

Ajout de migrations

Vous êtes maintenant prêt à ajouter votre première migration. Ouvrez la console du gestionnaire de packages et définissez comme projet par défaut le EFClassLibrary. Définissez également ce projet en tant que projet de démarrage (cliquez avec le bouton droit de la souris sur le projet et cliquez sur l'entrée Définir comme projet de démarrage).

Type

PM> Add-Migration Initial

puis

PM> Update-Database

3. Projet WPF App

Nom: WpfApp1.

Tapez: application WPF à l'aide de .NET Framework 4.7.

Dépendances

Dans ce projet, je n'ai ajouté aucun fichier. A vient de modifier le fichier MainWindow.xaml.cs pour vérifier que tout fonctionne correctement.

MainWindow.xaml.cs

using ClassLibrary1;
using EFClassLibrary;
using System.Windows;

namespace WpfApp1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            var db = new ClientDbContext();

            db.People.Add(new Person()
            {
                Name = "Omar"
            });

            db.SaveChanges();
        }
    }
}

J'espère que ça aide :)

9
OmarMuscatello

Ce que Microsoft suggère ici est de créer une nouvelle bibliothèque de classes pour les migrations, puis de déplacer vos fichiers de captures instantanées de modèles et vos migrations vers la nouvelle bibliothèque de classes.

Si vous n'en avez pas ajouté, ajoutez-en un au projet DbContext puis déplacez-le.

Puis configurez la migration Assembly:

options.UseSqlServer(
    connectionString,
    x => x.MigrationsAssembly("MyApp.Migrations"));

Et ajoutez ensuite une référence à votre Assemblée de migration à partir de votre Assemblée de démarrage:

Remarque:

Si cela provoque une dépendance circulaire, mettez à jour le chemin de sortie de la bibliothèque de classes:

<PropertyGroup>
  <OutputPath>..\MyStarupProject\bin\$(Configuration)\</OutputPath>
</PropertyGroup>

pour une deuxième référence, utilisez Le guide de Ben Cull sur la migration EntityFramework Core pour les projets de bibliothèque de classes.

3
Barr J

Dans votre projet de démarrage, vous devez créer une fabrique qui implémentera IDesignTimeDbContextFactory et créera le DBContext pour vous.

public class DBContextFactory : IDesignTimeDbContextFactory<DBContext>
        {
            public DBContext CreateDbContext(string[] args)
            {
                var optionsBuilder = new DbContextOptionsBuilder<DBContext>();

                // Row numbers for paging adds support for old SQL server 2005+. See more: 
                // https://docs.Microsoft.com/en-us/ef/core/api/Microsoft.entityframeworkcore.infrastructure.sqlserverdbcontextoptionsbuilder
                optionsBuilder.UseSqlServer("Server=localhost;Database=DatabaseName;Trusted_Connection=True;MultipleActiveResultSets=true;Integrated Security=SSPI", x => x.UseRowNumberForPaging());

                return new DBContext(optionsBuilder.Options);
            }
        }
2
Gaurav Jalan

Ce qui a fonctionné pour moi, c’est de faire vos tâches habituelles sur votre interface utilisateur côté démarrage.s

services.AddDbContext<ShentonEvaDbContext>(options =>
                options.UseSqlServer(
                    _configuration.GetConnectionString("DevelopmentConnection")));

Ensuite, sur votre configuration DBContext, ajoutez simplement un constructeur

public ShentonEvaDbContext(DbContextOptions<ShentonEvaDbContext> options) : base(options)
        {

        }

Après cela, sur la console de votre gestionnaire de packages, exécutez simplement la commande suivante:

dotnet ef migrations add InitialMigration --project "NameOfDbContextProject" --startup-project "NameOfWebUIProject"

Ensuite, Everytihng a été ajouté et fait de même pour la mise à jour de la base de données.

1
Alexander Burias