如何在 Xamarin Forms 项目中为 Entity Framework 添加迁移?

How to add migrations for Entity Framework in a Xamarin Forms project?

我正在尝试让 EF 迁移在 Xamarin Forms 项目中工作。我有一个 SQLite 数据库的 DbContext:

    public class TestDbContext : DbContext
    {
        public DbSet<Item> Items { get; set; }

        public TestDbContext()
        {
            SQLitePCL.Batteries_V2.Init();

            this.Database.EnsureCreated();
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            string dbPath = Path.Combine(FileSystem.AppDataDirectory, "testDb.db3");

            optionsBuilder
                .UseSqlite($"Filename={dbPath}");
        }
    }

我为标准库安装了 Microsoft.EntityFrameworkCore.Tools nuget,但它不起作用。从 , I added a Dummy .NET Core 项目开始。

  1. 我在 Dummy(Xamarin Forms 项目)中引用了 .NET Standard 库 (2.1)
  2. 我也将 Microsoft.EntityFrameworkCore.SqliteMicrosoft.EntityFrameworkCore.Tools nuget 包安装到虚拟项目中
  3. 我在 .net 标准库中实现了一个 IDesignTimeDbContextFactory,如下所示:
    public class DesignTimeFactory : IDesignTimeDbContextFactory<TestDbContext>
    {
        public TestDbContext CreateDbContext(string[] args)
        {
            return new TestDbContext();
        }
    }

当我 运行 命令 PM> Add-Migration InitialCreate -P XamarinEFTest -S EFDummy 我得到一个异常:

Build started...
Build succeeded.
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> Xamarin.Essentials.NotImplementedInReferenceAssemblyException: This functionality is not implemented in the portable version of this assembly. You should reference the NuGet package from your main application project in order to reference the platform-specific implementation.
   at Xamarin.Essentials.FileSystem.get_PlatformAppDataDirectory()
   at Xamarin.Essentials.FileSystem.get_AppDataDirectory()
   at XamarinEFTest.TestDbContext.OnConfiguring(DbContextOptionsBuilder optionsBuilder) in C:\Users\szabk\source\repos\XamarinEFTest\XamarinEFTest\XamarinEFTest\TestDbContext.cs:line 24
   at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
   at Microsoft.EntityFrameworkCore.DbContext.Microsoft.EntityFrameworkCore.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance()
   at Microsoft.EntityFrameworkCore.Infrastructure.Internal.InfrastructureExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
   at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.get_Dependencies()
   at Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.EnsureCreated()
   at XamarinEFTest.TestDbContext..ctor() in C:\Users\szabk\source\repos\XamarinEFTest\XamarinEFTest\XamarinEFTest\TestDbContext.cs:line 19
   at XamarinEFTest.DesignTimeFactory.CreateDbContext(String[] args) in C:\Users\szabk\source\repos\XamarinEFTest\XamarinEFTest\XamarinEFTest\DesignTimeFactory.cs:line 12
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContextFromFactory(Type factory, Type contextType)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.<>c__DisplayClass16_0.<FindContextFactory>b__1()
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func`1 factory)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Exception has been thrown by the target of an invocation.

我有 VS 2019 16.8.4,我使用滑块菜单从布局模板创建了测试 xamarin 项目。

我需要做什么?

编辑:也许我需要使用不同的 SQLite 驱动程序和不同的 DesignTimeFactory 设置核心项目?但这将如何工作?最后,我需要迁移才能在 phone 中工作。

Xamarin.Essentials FileSystem.AppDataDirectory 在您尝试创建迁移的 Windows/Mac 上不起作用。

使用此 sqlite 数据库路径创建迁移:

optionsBuilder.UseSqlite($"Data Source=migrations.db3");

此路径是相对路径,您最终会在项目文件夹中创建一个 migrations.db3 文件。只需忽略 .db 文件,它的唯一目的是创建迁移。

编辑: 我一直在我的应用程序中使用这个 DbContext,它工作得很好。

public class MyDbContext : DbContext
{
    private string _databasePath;

    public DbSet<MyEntity> Issues { get; set; }

    [Obsolete("Don't use this for production. This is only for creating migrations.")]
    public MyDbContext() : this("nothing.db")
    {

    }

    public MyDbContext(string dbPath)
    {
        _databasePath = dbPath;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {
            optionsBuilder.UseSqlite($"Data Source={_databasePath}");
        }
    }
}