0

我使用 CleanArchitecture 解决方案。我有 ApplicationDbContext 和 UnitOfWork 所在的数据层:

namespace Portal.Data.MyDbContexts
{
    internal class ApplicationDbContext : DbContext
    {

        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
        {
            Database.EnsureCreated();
        }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.ApplyConfigurationsFromAssembly(typeof(BaseEntity).Assembly);
        }


        // **********
        public DbSet<WebsiteMonitoredCategory> WebsiteMonitoredCategories { get; set; }
        // **********


        
    }

工作单元:

public abstract class BaseUnitOfWork : object, IBaseUnitOfWork
    {
        //public UnitOfWork() : base()
        //{
        //}

        public BaseUnitOfWork(Options options) : base()
        {
            Options = options;
        }

        // **********
        protected Options Options { get; set; }
        // **********

        // **********
        // **********
        // **********
        private ApplicationDbContext _databaseContext;
        // **********

        // **********
        /// <summary>
        /// Lazy Loading = Lazy Initialization
        /// </summary>
        internal ApplicationDbContext DatabaseContext
        {
            get
            {
                if (_databaseContext == null)
                {
                    var optionsBuilder =
                        new DbContextOptionsBuilder<ApplicationDbContext>();

                    switch (Options.Provider)
                    {
                        case Provider.SqlServer:
                            {
                                optionsBuilder.UseSqlServer
                                    (connectionString: Options.ConnectionString);

                                break;
                            }

                        case Provider.MySql:
                            {
                                //optionsBuilder.UseMySql
                                //  (connectionString: Options.ConnectionString);

                                break;
                            }

                        case Provider.Oracle:
                            {
                                //optionsBuilder.UseOracle
                                //  (connectionString: Options.ConnectionString);

                                break;
                            }

                        case Provider.PostgreSQL:
                            {
                                //optionsBuilder.UsePostgreSQL
                                //  (connectionString: Options.ConnectionString);

                                break;
                            }

                        case Provider.InMemory:
                            {
                                optionsBuilder.UseInMemoryDatabase(databaseName: "Temp");

                                break;
                            }

                        default:
                            {
                                break;
                            }
                    }

                    _databaseContext =
                        new ApplicationDbContext(options: optionsBuilder.Options);
                }

                return _databaseContext;
            }
        }

我也有 IoC 层,用于向表示层注入依赖项:

public class DependencyContainer
    {
        public static void RegisterServices(IServiceCollection services,IConfiguration configuration)
        {

            
            //DataLayer
            services.AddTransient<IUnitOfWork, UnitOfWork>(_ =>
            {
                Options options =
                    new Options
                    {
                        Provider =
                            (Provider)System.Convert.ToInt32(configuration.GetSection(key: "DatabaseProvider").Value),

                    

                        ConnectionString =
                            configuration.GetSection(key: "ConnectionStrings").GetSection(key: "MyConnectionString").Value,
                    };

                return new UnitOfWork(options: options);
            });


        }
    }

最后我有一个 Windows 窗体应用程序 Net 5.0(所有项目都是 Net5.0)

namespace Portal.Desktop
{
    public static class Program
    {
        private static IConfiguration Configuration { get; set; }
        public static IServiceProvider ServiceProvider { get; set; }
        /// <summary>
        ///  The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            var services = ConfigureServices();

            var builder = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
            Configuration = builder.Build();

            
        

            Application.SetHighDpiMode(HighDpiMode.SystemAware);
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm());
            RegisterServices(services, Configuration);
        }

        public static void RegisterServices(IServiceCollection services, IConfiguration configuration)
        {
            DependencyContainer.RegisterServices(services, configuration);
        }

        public static IServiceCollection ConfigureServices()
        {
            var services = new ServiceCollection();
            //services.AddTransient<IUnitOfWork, UnitOfWork>(_ =>
            //{
            //  Options options =
            //      new Options
            //      {
            //          Provider =
            //              (Provider)System.Convert.ToInt32(Configuration.GetSection(key: "DatabaseProvider").Value),

            //          //using Microsoft.EntityFrameworkCore;
            //          //ConnectionString =
            //          //  Configuration.GetConnectionString().GetSection(key: "MyConnectionString").Value,

            //          ConnectionString =
            //              Configuration.GetSection(key: "ConnectionStrings").GetSection(key: "MyConnectionString").Value,
            //      };

            //  return new Portal.Data.UoW.UnitOfWork(options: options);
            //});


            ServiceProvider = services.BuildServiceProvider();

            return services;
        }
    }
}

我使用 Ef core 5.0 ,windows forms 设置为启动项目,包管理器控制台设置为 Protal.Data (dbcontext 和 unitofwork 在那里)但是当我在 PMC 中运行Add-Migration inti 时出现错误:

无法创建“ApplicationDbContext”类型的对象。有关设计时支持的不同模式,请参阅 https://go.microsoft.com/fwlink/?linkid=851728

在数据层安装了这个包:

<ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.7" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.7">
        <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="5.0.7" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.7" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.7">
        <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
  </ItemGroup>

不知道为什么,给我一个错误。

- - -更新 - -

我遵循https://go.microsoft.com/fwlink/?linkid=851728并将ApplicationDbContextFactory.cs添加到 Portal.Desktop (windows forms Net5.0) 项目:

namespace Portal.Desktop
{
    public class ApplicationDbContextFactory:IDesignTimeDbContextFactory<ApplicationDbContext>
    {
        public ApplicationDbContext CreateDbContext(string[] args)
        {
            var connectionString = Program.Configuration.GetSection(key: "ConnectionStrings").GetSection(key: "MyConnectionString").Value;
            var provider = Program.Configuration.GetSection(key: "DatabaseProvider").Value;
            var optionsBuilder =
                new DbContextOptionsBuilder<ApplicationDbContext>();
            var options =
                new Options
                {
                    Provider =
                        (Provider)System.Convert.ToInt32(provider),

                    //using Microsoft.EntityFrameworkCore;
                    //ConnectionString =
                    //  Configuration.GetConnectionString().GetSection(key: "MyConnectionString").Value,

                    ConnectionString = connectionString,
                };
            switch (options.Provider)
            {
                case Provider.SqlServer:
                {
                    optionsBuilder.UseSqlServer
                        (connectionString: options.ConnectionString);

                    break;
                }

                case Provider.MySql:
                {
                    //optionsBuilder.UseMySql
                    //  (connectionString: Options.ConnectionString);

                    break;
                }

                case Provider.Oracle:
                {
                    //optionsBuilder.UseOracle
                    //  (connectionString: Options.ConnectionString);

                    break;
                }

                case Provider.PostgreSQL:
                {
                    //optionsBuilder.UsePostgreSQL
                    //  (connectionString: Options.ConnectionString);

                    break;
                }

                case Provider.InMemory:
                {
                    optionsBuilder.UseInMemoryDatabase(databaseName: "Temp");

                    break;
                }

                default:
                {
                    break;
                }
            }

            return 
                new ApplicationDbContext(options: optionsBuilder.Options);
        }
    }
}

当我想添加迁移时,核心抛出异常已被调用的目标抛出。例外:

System.Reflection.TargetInvocationException:调用的目标已引发异常。---> System.NullReferenceException:对象引用未设置为对象的实例。在 Portal.Desktop.ApplicationDbContextFactory.CreateDbContext(String[] args) 在 C:\Users\Arman Es\source\repos\Spider\Portal.Desktop\ApplicationDbContextFactory.cs:line 20 --- 内部异常堆栈跟踪结束 -- - 在 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, CultureInfoculture )
在 System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters) 在 Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContextFromFactory(Type factory, Type contextType) 在 Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.<>c__DisplayClass13_2 .b__9() 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_01.b__0() at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action) 调用的目标已引发异常。

4

1 回答 1

1

最后,我在这篇文章中找到了答案https://snede.net/you-dont-need-a-idesigntimedbcontextfactory/

在 Portal.Data 项目中创建ApplicationDbContextFactory :

using System.IO;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
using Portal.Domain.Tools;
using Portal.Domain.Tools.Enums;

namespace Portal.Data.MyDbContexts
{
    public class ApplicationDbContextFactory:IDesignTimeDbContextFactory<ApplicationDbContext>
    {
        private IConfiguration Configuration { get; set; }

        public ApplicationDbContext CreateDbContext(string[] args)
        {

            var builder = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json");
            Configuration = builder.Build();

            var optionsBuilder =
                new DbContextOptionsBuilder<ApplicationDbContext>();
            var options =
                new Options
                {
                    Provider =
                        (Provider)System.Convert.ToInt32(Configuration.GetSection(key: "DatabaseProvider").Value),
                    ConnectionString = Configuration.GetSection(key: "ConnectionStrings").GetSection(key: "MyConnectionString").Value
                };

            switch (options.Provider)
            {
                case Provider.SqlServer:
                {
                    optionsBuilder.UseSqlServer
                        (connectionString: options.ConnectionString);

                    break;
                }

                case Provider.MySql:
                {
                    //optionsBuilder.UseMySql
                    //  (connectionString: Options.ConnectionString);

                    break;
                }

                case Provider.Oracle:
                {
                    //optionsBuilder.UseOracle
                    //  (connectionString: Options.ConnectionString);

                    break;
                }

                case Provider.PostgreSQL:
                {
                    //optionsBuilder.UsePostgreSQL
                    //  (connectionString: Options.ConnectionString);

                    break;
                }

                case Provider.InMemory:
                {
                    optionsBuilder.UseInMemoryDatabase(databaseName: "Temp");

                    break;
                }

                default:
                {
                    break;
                }
            }

            return 
                new ApplicationDbContext(options: optionsBuilder.Options);
        }
    }
}

appsettings.json仍在 Portal.Desktop 项目中:

namespace Portal.Desktop
{
    public static class Program
    {
        public  static IConfiguration Configuration { get; set; }
        public static IServiceProvider ServiceProvider { get; set; }
        /// <summary>
        ///  The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            var services = ConfigureServices();

            RegisterServices(services, Configuration);


            Application.SetHighDpiMode(HighDpiMode.SystemAware);
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm());
            
        }

        public static void RegisterServices(IServiceCollection services, IConfiguration configuration)
        {
            DependencyContainer.RegisterServices(services, configuration);
        }

        public static IServiceCollection ConfigureServices()
        {
            var services = new ServiceCollection();
            

            ServiceProvider = services.BuildServiceProvider();

            return services;
        }
    }
}

最后IoC项目是:

namespace Portal.IoC
{
    public class DependencyContainer
    {
        public static void RegisterServices(IServiceCollection services,IConfiguration configuration)
        {

            //DataLayer
            services.AddTransient<IUnitOfWork, UnitOfWork>(_ =>
            {
                var options =
                    new Options
                    {
                        Provider =
                            (Provider)System.Convert.ToInt32(configuration.GetSection(key: "DatabaseProvider").Value),
                        ConnectionString =
                            configuration.GetSection(key: "ConnectionStrings").GetSection(key: "MyConnectionString").Value,
                    };

                return new UnitOfWork(options: options);
            });

        


        }
    }
}
于 2021-06-13T12:31:16.063 回答