【问题标题】:Using Entity Framework Core migrations for class library project对类库项目使用 Entity Framework Core 迁移
【发布时间】:2019-06-21 17:41:53
【问题描述】:

这似乎是an issue that have been fixed already,至少对于 SQLite 数据库而言。

我的解决方案包括 3 个项目:

  1. WPF 项目(默认启动项目)(.NET Framework 4.7),
  2. 包含视图模型和非 UI 内容的“核心”项目 - 类库项目 (.NET Standard 2.0)
  3. “关系”项目包含所有实体框架数据层 - 我喜欢将它们分开(.NET Standard 2.0

我已将以下包安装到主 WPF 项目中:

Microsoft.EntityFrameworkCore.Tools
Microsoft.EntityFrameworkCore.Design

项目 2 和 3 在我的主要 WPF 项目中被引用。所以基本上,EF 解决 DbContextes 就足够了。

但是,它不是 - 因为在我的 WPF 项目上运行 Add-Migration 会导致:

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.

在包管理器控制台中默认切换到项目 3 会导致:

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.

如何在我的类库项目和 WPF 项目中正确使用 EF Core 迁移?

【问题讨论】:

    标签: c# entity-framework visual-studio-2017 .net-core entity-framework-core


    【解决方案1】:

    我复制了您的解决方案并找到了...一个解决方案:)

    1. “核心”项目 - 名为 ClassLibrary1
    2. “关系”项目 - 称为 EFClssLibrary
    3. WPF 应用项目 - 名为 WpfApp1

    让我们深入。


    1。核心项目

    名称ClassLibrary1

    类型.NET Standard 2.0 类库

    依赖项:无。

    在我的测试解决方案中,它只包含一个类,一个名为Person的模型。

    Person.cs

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

    2。关系项目

    名称EFClassLibrary

    类型.NET Standard 2.0 类库

    依赖关系

    这个项目,在我的测试解决方案中,只包含一个类:数据库上下文。

    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);
            }
        }
    }
    

    连接字符串

    在这个类中定义了一个使用连接字符串连接到数据库(假设它是 LocalDb SQL Server)。如果要将连接字符串放在配置文件中,可以在解决方案中添加共享配置文件,然后在 App.config 文件中引用该文件(有关更多信息,请查看 this page

    配置目标框架

    为了能够在此项目上添加迁移而不将其他项目设置为启动项目,您必须设置目标框架。右键单击项目并单击 Edit EFClassLibrary.csproj 条目。在&lt;TargetFramework&gt;netstandard2.0&lt;/TargetFramework&gt; 行下方,您应该添加另一行来指定您要定位的框架。要面向 .NET Framework 4.7,您应该添加

    <TargetFramework>net47</TargetFramework>
    

    所有允许值的列表可以在here找到。

    我的 EFClassLibrary.csproj 在添加 .NET Framework 4.7 作为目标后看起来像下面的代码。

    <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>
    

    添加迁移

    现在您已准备好添加您的第一个迁移。打开包管理器控制台并将 EFClassLibrary 设置为默认项目。另外,将该项目设置为启动项目(右键单击该项目并单击设置为启动项目条目)。

    类型

    PM> Add-Migration Initial
    

    然后

    PM> Update-Database
    

    3。 WPF 应用项目

    名称WpfApp1

    类型WPF 应用程序使用.NET Framework 4.7

    依赖关系

    在这个项目中,我没有添加任何文件。 A 刚刚编辑了MainWindow.xaml.cs 文件以检查一切是否正常。

    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();
            }
        }
    }
    

    希望对你有帮助:)

    【讨论】:

    • 美丽的答案。令人惊讶的是,它无需添加 &lt;TargetFramework&gt;net47&lt;/TargetFramework&gt; 行并将 WPF 项目设置为启动项目。不知道为什么它有效,但它确实有效。事实上,在这里真正有帮助的解决方案是:public ClientDbContext() : base() { } ... 因为我的 dbcontext 中只有选项构造函数。添加默认值后,它就像一个魅力。非常感谢您的努力。由于 SO 限制,我将在 14 小时后奖励您。
    • 很高兴为您提供帮助。谢谢你:)
    • 如果我的ClientDbContext 没有连接字符串怎么办。如果 connectionString 在 WPF 应用程序(或 MVC 应用程序)的配置中?如果我将 EFClassLibrary 设置为 StartUp 项目,我想迁移将不起作用。
    【解决方案2】:

    对我有用的只是在你的 UI 端 Startup.cs 上做你的常规工作

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

    然后在您的 DBContext 配置中添加一个构造函数

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

    之后在您的包管理器控制台上运行以下命令

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

    然后添加 Everytihng 并为更新数据库做同样的事情

    【讨论】:

      【解决方案3】:

      microsoft 建议在这里为迁移创建一个新的类库,然后将模型快照文件和迁移移动到新的类库。

      如果您还没有添加任何内容,请将其添加到 DbContext 项目然后移动它。

      然后配置迁移程序集:

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

      然后从您的启动程序集中添加对迁移程序集的引用:

      注意:

      如果这导致循环依赖,更新类库的输出路径:

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

      第二个参考使用Ben Cull's EntityFramework Core 迁移类库项目指南。

      【讨论】:

        【解决方案4】:

        在您的启动项目中,您必须创建一个工厂来实现 IDesignTimeDbContextFactory 并为您创建 DBContext。

        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);
                    }
                }
        

        【讨论】:

          【解决方案5】:

          我使用类库项目作为数据层和 asp.net 核心项目作为启动项目。首先我在 asp.net 启动类中注册了我的 E.F 核心上下文。

          public void ConfigureServices(IServiceCollection services)
          {
               //DataLayer namespace is in class library project
               services.AddDbContext<DataLayer.EFCoreContext>();
          }
          

          然后在我的上下文类(位于类库项目中)中,我从设置文件中提供了连接字符串并在 OnConfiguring 方法中使用它。

          public class EFCoreContext: DbContext
          {
                  private string ConnectionString { get; set; }
                  public EFCoreContext() : base()
                  { 
                      var settingsPath= AppDomain.CurrentDomain.BaseDirectory;
                      settingsPath +=  @"\datalayersettings.json";
                      var datalayersettings =File.ReadAllText(settingsPath);
                      dynamic jSetting = JObject.Parse(datalayersettings);
                      this.ConnectionString = 
                              (string)jSetting.ConnectionStrings.ConnectionString;
                  }
          
                  protected override void OnConfiguring(DbContextOptionsBuilder 
                                                        optionsBuilder)
                  {
                      optionsBuilder.UseSqlServer(this.ConnectionString);
                  }
          }
          

          然后为了应用迁移和更新数据库,我分别使用了以下命令

          add-migration MyEFCoreMigration -Context DataLayer.EFCoreContext -Project DataLayer
          
          Update-Database -Context DataLayer.EFCoreContext -Project DataLayer
          

          【讨论】:

            猜你喜欢
            • 2017-05-16
            • 2019-02-12
            • 1970-01-01
            • 2017-10-27
            • 1970-01-01
            • 2018-11-05
            • 2020-03-09
            • 2017-02-06
            • 1970-01-01
            相关资源
            最近更新 更多