簡體   English   中英

從通用類繼承

[英]Inherit from generic class

我有.net core 2.1項目。 還有我的存儲庫類,如下所示。 但是由於MyDbContext構造函數具有參數,因此出現如下錯誤。 當我刪除JwtHelper參數時,它運行良好。 但是,我需要增加JwtHelperMyDbContext.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。

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()的雙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>的最后一個參數始終是返回值

並且為了完整性:具有無效返回值的方法稱為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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM