C# Dotnet 核心 - 在构造函数中实现泛型 DBContext 的问题 [英] C# Dotnet core - Issues with implementing generic DBContext in constructor

查看:18
本文介绍了C# Dotnet 核心 - 在构造函数中实现泛型 DBContext 的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为从长期停工中恢复过来而苦苦挣扎.

I am struggling with this coming back from a long layoff.

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

I asked a question regarding the configuring of a DBContext in my generic base repository. Only after a user has logged in can I then construct a connection string so I cannot register a service in startup.cs - I have to use a constructor argument to instantiate my DBContext.

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

I got this answer which I thought would address the problem however I am getting an error in the following factory class:

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); 是:

The error is on the line return new T(optionsBuilder.Options); and is:

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

Cannot create an instance of the variable type 'T' because it does not have the new() constraint

推荐答案

即使添加了new()约束,最终也会出现如下错误

Even if you add new() constraint, you will end up with the following error

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

'T': cannot provide arguments when creating an instance of a variable type.

您获得的代码无效.

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

The new constraint specifies that any type argument in a generic class declaration must have a public parameterless constructor. To use the new constraint, the type cannot be abstract.

参考 新约束(C# 参考)

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

Another option to consider could be to use 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);
    }
}

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

This could be refactored further to separate concerns

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

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

这样建造者将成为工厂使用地点的责任.

so that the builder will become the responsibility of where the factory is being used.

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方法中注册为开放泛型

The factory can be registered as open generics in ConfigureServices method

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

这篇关于C# Dotnet 核心 - 在构造函数中实现泛型 DBContext 的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆