将Entity Framework Core迁移用于类库项目

时间:2018-07-03 02:15:32

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

至少对于SQLite数据库,它似乎是an issue that have been fixed already

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

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

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

Microsoft.EntityFrameworkCore.Tools
Microsoft.EntityFrameworkCore.Design

在我的主要WPF项目中引用了项目2和3。因此,基本上,EF足以解决DbContext。

但是,事实并非如此-在我的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.

在Package Manager控制台中默认切换到项目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迁移?

5 个答案:

答案 0 :(得分:12)

我复制了您的解决方案,然后发现了……解决方案:)

  1. “核心”项目-名为 ClassLibrary1
  2. “关系”项目-名为 EFClssLibrary
  3. WPF App项目-名为 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 条目。在<TargetFramework>netstandard2.0</TargetFramework>行下方,您应添加另一行,以指定要定位的框架。要定位.NET Framework 4.7,您应该添加

<TargetFramework>net47</TargetFramework>

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

将.NET Framework 4.7添加为目标后,我的 EFClassLibrary.csproj 类似于下面的代码。

<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

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

依赖项

在此项目中,我没有添加任何文件。刚刚编辑过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();
        }
    }
}

希望它会有所帮助:)

答案 1 :(得分:3)

在启动项目中,您必须创建一个工厂,该工厂将实现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);
            }
        }

答案 2 :(得分:3)

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

如果尚未添加任何内容,则将其添加到DbContext项目中,然后将其移动。

然后配置迁移程序集:

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

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

注意:

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

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

有关实体库项目的EntityFramework Core迁移的其他参考,请使用Ben Cull's指南。

答案 3 :(得分:3)

对我有用的只是在UI Side Startup.cs上做一些常规的事情

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

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

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

        }

之后,在Package Manager控制台上运行以下命令

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

然后添加Everytihng并为数据库更新执行相同操作

答案 4 :(得分:0)

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

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