[英]Inherit from generic class
我有.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>();
}
問題出在您的UnitOfWork
的構造函數中:
public UnitOfWork()
{
DataContext = new TContext();
}
在這里,您使用默認構造函數構造了MyDbContext
類的新對象,但是MyDbContext
沒有默認構造函數。
您決定使UnitOfWork
非常通用。 太好了,因為這使您可以將我們的UnitOfWork
與所有DbContexts
。 您告訴UnitOfWork
的唯一限制是DbContext
應該具有默認構造函數。
一個好的方法是自己創建工廠並將其傳遞給UnitOfWork。
如果您不希望或不能給MyDbContext
一個默認的構造函數,請考慮告訴您的UnitOfWork
如何創建它:“嘿,工作單元,如果您需要創建我要使用的DbContext,請使用此功能“
實際上,您將使用工廠設計模式
步驟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()
的雙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);
new()
約束需要無參數構造函數; 但是,因為你需要IJwtHelper
在你DbContext
,以及財產只有在存在MyDbContext
,你可以使自己的基類的,而不是獲得其他背景DbContext
:
public class MyDbContextBase : DbContext
{
public IJwtHelper JwtHelper { get; set; }
}
刪除IJwtHelper
物業MyDbContext
; 刪除構造函數; 使它繼承MyDbContextBase
而不是DbContext
將IUnitOfWork<U>
接口上的U
約束更改為MyDbContextBase
在UnitOfWork<TContext>
類MyDbContextBase
TContext
約束從DbContext
更改為MyDbContextBase
; 將IJwtHelper
添加為構造函數參數
一旦在UnitOfWork<TContext>
類的構造函數中實例化了TContext
,就IJwtHelper
通過public屬性分配IJwtHelper
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.