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

查看:201
本文介绍了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);
    }
}

错误在行返回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.

为您提供了无效的代码.

You were given invalid code.

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

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(类型,对象[]).

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天全站免登陆