具有类型 T 的通用构造函数的通用存储库

Generic repository with generic constructor of type T

我在 c# 中有以下 classes:

public class Customer{
  public long Id { get; set;}
  public String Firstname { get; set;}
  public String Lastname { get; set;}

  public Customer(long id, String firstname, String lastname){...}
}

public class Book{
  public long Id { get; set;}
  public String Title { get; set;}
  public String Author{ get; set;}
  public int NumberOfCopies{ get; set;}

  public Book(long id, String title, String author, int numberofcopies){...}
}

我的仓库是通用的,界面如下:

public interface IGenericRepository<T> where T : class, new(){

  Add(T entity);
  Update(T entity);
  Delete(T entity);
  GetAll();

}

因此,要为客户创建存储库,我会创建一个 IGenericRepository 并为一本书创建 IGenericRepository。要从 GUI 访问这些方法,我需要这样的方法:AddCustomer(long id, String firstname, String lastname) 和一本书一样,因为 GUI 不知道实体本身。我正在考虑创建一个包含这些方法的 CustomerService 和 BookService。 但是我必须为我添加的每个实体创建一个新服务。

我的问题是,如何使此服务通用并仍然保留来自实体构造函数的参数?

明确地说,我想要一个通用服务 class,它可以添加书籍和客户,但方法相同。例如:

Add(<constructor parameters of T>)

此方法将从控制器 class 调用,该控制器将拥有所有服务。然后 GUI 可以通过控制器访问这些服务方法。

这可能吗?如果是,如何?如果不是,是否有更好的解决方案来实现这一目标?

提前致谢!

一种选择是根据需要接受参数,例如。 g.:

public void Add<T>(params object param) { ... }

T 是您要创建的类型。通过反射检查哪些构造函数可用,选择适合参数列表的构造函数。然后实例化对象。瞧。

我会将 IRepository<t> 方法 Add(T entity) 更改为 Add(object entity)。这样您就可以对任何实体使用完全相同的代码。

我通常看到的方式是您具有以下内容:

1。 定义通用添加、更新、删除等的接口:

public interface IGenericRepository<T> where T : class
{
    Add(T entity);
    Update(T entity);
    Delete(T entity);
    GetAll();
}

2。 一个通用存储库,它接受您要持久保存到数据存储的不同类型。

public class GenericRepository<T> : IGenericRepository<T> where T : class
{
    private connectionInformation;

    public GenericRepository<T>(object connectionInformation)
    {
        // do something with the connection info, dbContext, etc...
    }

    public T Add(T entity)
    {
        // implementation...
    }

    public T Update(T entity)
    {
        // implementation...
    }

    public T Delete(T entity)
    {
        // implementation...
    }

    public List<T> GetAll()
    {
        // implementation...
    }
}

3。 为不同具体类型设置通用存储库实例的工作单元。

public class UnitOfWork
{
    private object connectionInformation;

    public UnitOfWork(object connectionInformation)
    {
        // set up your connection information
        this.connectionInformation = connectionInformation;

        this.CustomerRepository = new GenericRepository<Customer>(connectionInformation);

        this.BookRepository = new GenericRepository<Book>(connectionInformation);
    }

    public GenericRepository<Book> BookRepository { get; private set; }

    public GenericRepository<Customer> CustomerRepository { get; private set; }
}

4。 一个 service/services 层,可以实例化一个 "unit of work",您可以从中与之交互。该服务负责处理每种类型的不同属性,但数据保存和检索将通过 unitOfWork 处理。在您的服务中,您可以使用这样的方法:

public void DeleteFirstBook()
{
    var unitOfWork = new UnitOfWork(connnectionInformation);

    var books = unitOfWork.BookRepository.GetAll();

    if(books.Any())
    {
        unitOfWork.BookRepository.Delete(books.First());
    }
}

您也可以为客户做同样的事情。服务层就位可以帮助您的代码避免过于紧密的耦合。 "Data Layer" 应该只负责与数据库交互(创建、读取、更新、删除)。正如您所说,您的 UI 层也不应该知道如何创建新对象或与数据库交互。所以服务变得很重要,因为它知道如何设置数据,将数据放在哪里,以及如何 return 将其返回到 UI。

希望对您有所帮助!

非常标准的方法是将 "creator" 委托传递给您的存储库,我也不确定它是否符合您的目标:

public interface IGenericRepository<T> where T : class{

  Add(Func<T> creator);
  ...
}

Repository<T> : IGenericRepository<T> where T : class
{
     public  Add(Func<T> creator) 
     {
        T newOne = creator();
        ....
     }
}

// usage
bookRepository.Add(() => new Book(42, "some title", ...));