继承自泛型 class
Inherit from generic class
我有 .net core 2.1 项目。我的存储库 类 如下所示。但是因为 MyDbContext
构造函数有参数,我得到如下错误。当我删除 JwtHelper 参数时,它运行良好。 但是,我需要在 MyDbContext.cs
中添加 JwtHelper
来记录审核。 我怎样才能做到这一点?
'MyDbContext' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TContext' in the generic type or method 'UnitOfWork'
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();
}
}
我UnitOfWork.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)); } }
}
我MyRepos.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;
}
}
我UserRepository.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>();
}
new()
约束需要无参数构造函数;但是,由于您在 DbContext
中需要 IJwtHelper
,而 属性 仅存在于 MyDbContext
中,您可以创建自己的基础 class 以从中派生其他上下文而不是 DbContext
:
public class MyDbContextBase : DbContext
{
public IJwtHelper JwtHelper { get; set; }
}
从MyDbContext
中删除IJwtHelper
属性;删除构造函数;让它继承 MyDbContextBase
而不是 DbContext
将IUnitOfWork<U>
接口上的U
约束改为MyDbContextBase
在 UnitOfWork<TContext>
class 上将 TContext
约束从 DbContext
更改为 MyDbContextBase
;添加 IJwtHelper
作为构造函数参数
在UnitOfWork<TContext>
class的构造函数中实例化TContext
后,通过public[=55]赋值IJwtHelper
=].
问题出在你的 UnitOfWork
:
的构造函数中
public UnitOfWork()
{
DataContext = new TContext();
}
此处使用默认构造函数构造class MyDbContext
的新对象,但MyDbContext
没有默认构造函数。
您决定让您的 UnitOfWork
非常通用。这很好,因为这使您能够将我们的 UnitOfWork
与各种 DbContexts
一起使用。你告诉你的 UnitOfWork
的唯一限制是你的 DbContext
应该有一个默认构造函数。
一个好的方法是自己创建工厂并将其传递给 UnitOfWork。
如果您不想或不能给 MyDbContext
默认构造函数,请考虑告诉您的 UnitOfWork
如何创建一个:"Hey unit of work, if you need to create the DbContext that I want you to use, use this function"
事实上,您将使用 factory design pattern
老式的界面方法
第 1 步:使用函数 Create()
创建一个 class,它将准确创建您要使用的 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。
Lambda 表达式
您实际上不必实现接口。您的 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()
.
的双 return 值
有点跑题了:Lambda表达式的解释
类似地,如果您需要创建一个 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> 的最后一个参数始终是 return 值
为了完整起见:具有 void return 的方法称为 Action:
Action(Rectangle) displayRectangle = (r) => this.Form.DrawRectangle(r);
我有 .net core 2.1 项目。我的存储库 类 如下所示。但是因为 MyDbContext
构造函数有参数,我得到如下错误。当我删除 JwtHelper 参数时,它运行良好。 但是,我需要在 MyDbContext.cs
中添加 JwtHelper
来记录审核。 我怎样才能做到这一点?
'MyDbContext' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TContext' in the generic type or method 'UnitOfWork'
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();
}
}
我UnitOfWork.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)); } }
}
我MyRepos.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;
}
}
我UserRepository.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>();
}
new()
约束需要无参数构造函数;但是,由于您在 DbContext
中需要 IJwtHelper
,而 属性 仅存在于 MyDbContext
中,您可以创建自己的基础 class 以从中派生其他上下文而不是 DbContext
:
public class MyDbContextBase : DbContext
{
public IJwtHelper JwtHelper { get; set; }
}
从
MyDbContext
中删除IJwtHelper
属性;删除构造函数;让它继承MyDbContextBase
而不是DbContext
将
IUnitOfWork<U>
接口上的U
约束改为MyDbContextBase
在
UnitOfWork<TContext>
class 上将TContext
约束从DbContext
更改为MyDbContextBase
;添加IJwtHelper
作为构造函数参数在
UnitOfWork<TContext>
class的构造函数中实例化TContext
后,通过public[=55]赋值IJwtHelper
=].
问题出在你的 UnitOfWork
:
public UnitOfWork()
{
DataContext = new TContext();
}
此处使用默认构造函数构造class MyDbContext
的新对象,但MyDbContext
没有默认构造函数。
您决定让您的 UnitOfWork
非常通用。这很好,因为这使您能够将我们的 UnitOfWork
与各种 DbContexts
一起使用。你告诉你的 UnitOfWork
的唯一限制是你的 DbContext
应该有一个默认构造函数。
一个好的方法是自己创建工厂并将其传递给 UnitOfWork。
如果您不想或不能给 MyDbContext
默认构造函数,请考虑告诉您的 UnitOfWork
如何创建一个:"Hey unit of work, if you need to create the DbContext that I want you to use, use this function"
事实上,您将使用 factory design pattern
老式的界面方法
第 1 步:使用函数 Create()
创建一个 class,它将准确创建您要使用的 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。
Lambda 表达式
您实际上不必实现接口。您的 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表达式的解释
类似地,如果您需要创建一个 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> 的最后一个参数始终是 return 值
为了完整起见:具有 void return 的方法称为 Action:
Action(Rectangle) displayRectangle = (r) => this.Form.DrawRectangle(r);