具有类型 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", ...));
我在 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
我的问题是,如何使此服务通用并仍然保留来自实体构造函数的参数?
明确地说,我想要一个通用服务 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", ...));