【问题标题】:C# Dotnet core - Issues with implementing generic DBContext in constructorC# Dotnet 核心 - 在构造函数中实现通用 DBContext 的问题
【发布时间】:2019-04-28 02:03:52
【问题描述】:

我正在努力解决这个问题。

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

错误就行 return new T(optionsBuilder.Options); 是:

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

【问题讨论】:

  • 即使你添加了new() 约束,你最终也会得到'T': cannot provide arguments when creating an instance of a variable type。您获得了无效代码。

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


【解决方案1】:

即使添加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<>));

【讨论】:

  • 我想我需要在启动时将工厂注册为单例 - 如果是这样怎么办?
  • @Nkosi:感谢您发现我为回答 Simon 的原始问题而提供的代码中的错误。我已经编辑了答案以显示如何将工厂注册为开放泛型。
  • @si2030 请查看原始问题的更新答案。
  • 谢谢。但是,此代码在我的项目中不起作用。我这样编码 services.AddTransient(typeof(DatabaseContextFactory));它在我的项目中起作用
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-19
  • 1970-01-01
  • 2019-09-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多