我有.net core 2.1项目。还有我的存储库类,如下所示。但是由于MyDbContext
构造函数具有参数,因此出现如下错误。当我删除JwtHelper参数时,它运行良好。 但是,我需要在JwtHelper
中添加MyDbContext.cs
来记录审核。如何实现?
“ MyDbContext”必须是具有公共无参数构造函数的非抽象类型,以便在通用类型或方法“ UnitOfWork”中将其用作参数“ TContext”
UnitOfWork.cs
public class UnitOfWork<TContext> : IUnitOfWork<TContext> where TContext : DbContext, new()
{
protected readonly DbContext DataContext;
public UnitOfWork()
{
DataContext = new TContext();
}
public virtual async Task<int> CompleteAsync()
{
return await DataContext.SaveChangesAsync();
}
public void Dispose()
{
DataContext?.Dispose();
}
}
IUnitOfWork.cs
public interface IUnitOfWork<U> where U : DbContext
{
Task<int> CompleteAsync();
}
MyRepos.cs
public class MyRepos : UnitOfWork<MyDbContext>, IMyRepos
{
private IUserRepository userRepo;
public IUserRepository UserRepo { get { return userRepo ?? (userRepo = new UserRepository(DataContext)); } }
}
IMyRepos.cs
public interface IMyRepos : IUnitOfWork<MyDbContext>
{
IUserRepository UserRepo { get; }
}
MyDbContext.cs
public class MyDbContext : DbContext
{
private readonly IJwtHelper jwtHelper;
public MyDbContext(IJwtHelper jwtHelper) : base()
{
this.jwtHelper= jwtHelper;
}
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
{
var userId=jwtHelper.GetUserId();
SaveAudits(userId,base.ChangeTracker);
return (await base.SaveChangesAsync(true, cancellationToken));
}
}
UserRepository.cs
public class UserRepository : Repository<User>, IUserRepository
{
private readonly MyDbContext_context;
public UserRepository(DbContext context) : base(context)
{
_context = _context ?? (MyDbContext)context;
}
}
IUserRepository.cs
public interface IUserRepository : IRepository<User>
{ }
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IJwtHelper, JwtHelper>();
services.AddScoped<DbContext, MyDbContext>();
services.AddTransient<IMyRepos, MyRepos>();
}
答案 0 :(得分:2)
问题出在您的UnitOfWork
的构造函数中:
public UnitOfWork()
{
DataContext = new TContext();
}
这里您使用默认构造函数构造了类MyDbContext
的新对象,但是MyDbContext
没有默认构造函数。
您决定使您的UnitOfWork
非常通用。太好了,因为这使您可以将我们的UnitOfWork
与各种DbContexts
一起使用。您告诉UnitOfWork
的唯一限制是DbContext
应该具有默认构造函数。
一个好的方法是自己创建工厂并将其传递给UnitOfWork。
如果您不希望或不能给MyDbContext
一个默认的构造函数,请考虑告诉您的UnitOfWork
如何创建一个构造函数:“嘿,工作单元,如果您需要创建一个我要您使用的DbContext,请使用此功能”
实际上,您将使用factory design pattern
步骤1:使用函数Create()
创建一个类,该类将完全创建您要使用的DbContext。
interface IDbContextFactory<TContext>
where TContext : DbContext
{
DbContext Create();
}
// The MyDbContextFactory is a factory that upon request will create one MyDbcontext object
// passing the JwtHelper in the constructor of MyDbContext
class MyDbContextFactory : IDbContextFactory<MyDbContext>
{
public IJwthHelper JwtHelper {get; set;}
public MyDbContext Create()
{
return new MyDbContext(this.JwtHelper);
}
DbContext IDbContextFactory<HsysDbContext>.Create()
{
throw new NotImplementedException();
}
}
第2步:告诉您的UnitOfWork如何创建DbContext。
public class UnitOfWork<TContext> : IUnitOfWork<TContext> where TContext : DbContext
{
public static IDbContextFactory<TContext> DbContextFactory {get; set;}
protected readonly DbContext DataContext;
public UnitOfWork()
{
this.DataContext = dbContextFactory.Create();
}
...
}
public void ConfigureServices(IServiceCollection services)
{
// create a factory that creates MyDbContexts, with a specific JwtHelper
IJwtHelper jwtHelper = ...
var factory = new MyDbContextFactory
{
JwtHelper = jwtHelper,
}
// Tell the UnitOfWork class that whenever it has to create a MyDbContext
// it should use this factory
UnitOfWork<MyDbContext>.DbContextFactory = factory;
... // etc
}
从现在开始,每当构建UnitOfWork<MyDbContext>
对象时,
使用默认构造函数,此构造函数将命令工厂创建一个新的MyDbContext。
您实际上不必实现接口。您的UnitOfWork只需要知道如何创建DbContext。
您可以通过Func代替接口:
public class UnitOfWork<TContext> : IUnitOfWork<TContext> where TContext : DbContext
{
// use this function to create a DbContext:
public static Func<TContext> CreateDbContextFunction {get; set;}
protected readonly DbContext DataContext;
public UnitOfWork()
{
// call the CreateDbContextFunction. It will create a fresh DbContext for you:
this.DataContext = CreateDbContextFunction();
}
}
public void ConfigureServices(IServiceCollection services)
{
// create a factory that creates MyDbContexts, with a specific JwtHelper
IJwtHelper jwtHelper = ...
var factory = new MyDbContextFactory
{
JwtHelper = jwtHelper,
}
// Tell the UnitOfWork class that whenever it has to create a MyDbContext
// it should use this factory
UnitOfWork<MyDbContext>.CreateDbContextFunction = () => factory.Create();
在评论后添加
最后一条语句中的部分() => factory.Create();
称为lambda表达式。这意味着:创建一个没有输入参数(即()
部分)和等于factory.Create()
的双精度返回值的函数。
类似地,如果您需要创建一个lambda表达式来表示一个函数,该函数的输入参数为Rectangle并作为矩形的表面输出:
Func<Rectangle, double> myFunc = (rectangle) => rectangle.X * rectangle.Y;
用词来说:myFunc是一个函数,其输入为Rectangle,输出为double。功能类似于:
double MyFunc (Rectangle rectangle)
{
return rectangle.X * rectangle.Y;
}
您这样称呼它:
Func<Rectangle, double> calcSurface = (rectangle) => rectangle.X * rectangle.Y;
Rectangle r = ...;
double surface = calcSurface(r);
同样,一个lambda表达式表示具有两个输入参数和一个输出参数的函数:
Func<double, double, Rectangle> createRectangle =
(width, height) => new Rectangle {Width = width, Height = height};
Func <...,...,...,x>的最后一个参数始终是返回值
为了完整起见:具有空返回值的方法称为Action:
Action(Rectangle) displayRectangle = (r) => this.Form.DrawRectangle(r);
答案 1 :(得分:1)
new()
约束需要无参数构造函数;但是,由于您需要在IJwtHelper
中使用DbContext
,并且该属性仅存在于MyDbContext
中,因此您可以使自己的基类代替DbContext
来派生其他上下文:
public class MyDbContextBase : DbContext
{
public IJwtHelper JwtHelper { get; set; }
}
从IJwtHelper
移除MyDbContext
属性;删除构造函数;使它继承MyDbContextBase
而不是DbContext
将U
界面上的IUnitOfWork<U>
约束更改为MyDbContextBase
将TContext
类的DbContext
约束从MyDbContextBase
更改为UnitOfWork<TContext>
;将IJwtHelper
添加为构造函数参数
在TContext
类的构造函数中实例化UnitOfWork<TContext>
后,请通过public属性分配IJwtHelper
。