C#Dotnet核心-在构造函数中实现通用DBContext的问题

时间:2019-04-28 02:03:53

标签: c# generics asp.net-core entity-framework-core

我正在努力从长期裁员中恢复过来。

我向question询问了有关在我的通用基础存储库中配置DBContext的问题。只有在用户登录后,我才能构造连接字符串,以便无法在startup.cs中注册服务-我必须使用构造函数参数来实例化我的DBContext。

我得到了这个answer,我以为可以解决该问题,但是在以下工厂类中却遇到了错误:

public class ContextFactory<T> : IContextFactory<T> : where T : DbContext
{
    public T CreateDbContext(string connectionString)
    {
        var optionsBuilder = new DbContextOptionsBuilder<T>();
        optionsBuilder.UseSqlServer(connectionString);
        return new T(optionsBuilder.Options);
    }
}

错误在行返回new T(optionsBuilder.Options);上,并且是:

  

无法创建变量类型“ T”的实例,因为它没有   有new()约束

1 个答案:

答案 0 :(得分:4)

即使添加了new()约束,您仍然会遇到以下错误

  

'T':创建变量类型的实例时不能提供参数。

为您提供了无效的代码。

  

新约束指定通用类声明中的任何类型参数都必须具有公共的无参数构造函数。要使用新的约束,类型不能为抽象。

引用new constraint (C# Reference)

要考虑的另一种选择是使用Activator.CreateInstance (Type, Object[])

给予

public interface IContextFactory<TContext> where TContext : DbContext {
    TContext Create(string connectionString);
}

您将按以下方式实现

public class ContextFactory<TContext> : IContextFactory<TContext>
    where TContext : DbContext {

    public TContext Create(string connectionString) {
        var optionsBuilder = new DbContextOptionsBuilder<TContext>();
        optionsBuilder.UseSqlServer(connectionString);
        return (TContext)Activator.CreateInstance(typeof(TContext), optionsBuilder.Options);
    }
}

可以将其进一步重构以分离关注点

public class ContextFactory<TContext> : IContextFactory<TContext>
    where TContext : DbContext {

    public TContext Create(DbContextOptions<TContext> options) {
        return (TContext)Activator.CreateInstance(typeof(TContext), options);
    }
}

以便建筑商将负责使用工厂。

var connection = @"....";
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlServer(connection);

//Assuming factory is `IContextFactory<BloggingContext>`    
using (var context = factory.Create(optionsBuilder.Options))
{
   // do stuff
}

编辑

可以通过ConfigureServices方法将工厂注册为开放的泛型

services.AddSingleton(typeof(IContextFactory<>), typeof(ContextFactory<>));