如何设计数据库接口
本文关键字:数据库 接口 | 更新日期: 2023-09-27 18:25:58
为了提供对数据库中对象的访问,我为所有团队成员创建了一个接口,如下所示(简化示例):
public interface IDatabase
{
ObservableCollection<Animal> Animals{ get; }
}
我不希望团队访问像数据库上下文或一些oracle对象(封装)这样的内部。。。
我实现了两个具体的类,用于实际生活和单元测试:
public class TestDatabase : IDatabase
{ }
public class OracleDatabase : IDatabase
{ }
经过一些使用后,团队成员要求越来越多的功能,我不得不在我的界面中添加方法:
public interface IDatabase
{
ObservableCollection<Animal> Animals{ get; }
ObservableCollection<Animal> Animals(Gender gender);
ObservableCollection<Animal> Animals(Gender gender, Race race);
}
一些过滤和排序工作当然可以由开发人员自己完成,但最好位于数据库中。
我现在的问题是,我的界面正在爆炸,它每天都有越来越多的专业功能,它远非稳定,而且一直在变化。
我的设计从一开始就有缺陷吗
解决这个问题的一些想法:
- 向所有开发人员公开数据库上下文对象(我认为这很糟糕)
- 添加一个接受linq查询的函数
您正在尝试重新发明Repository/UnitOfWork模式,但您做的并不完全正确。
一个正确的方法接近于此:
// shared between repositories
public interface IGenericRepository<T>
{
T CreateNew();
void Delete( T item );
void Update( T item );
void Insert( T item );
IEnumerable<T> FindAll();
T FindOne( int id );
}
// specific repositories
public interface IAnimalRepository : IGenericRepository<Animal>
{
IEnumerable<Animal> FindByNumberOfLegs( int NumberOfLegs );
// ... anything specific follows
}
public interface IHumanRepository : IGenericRepository<Human>
{
IEnumerable<Human> FindByGender( Gender gender );
// ... specific repository logic follows
}
// unit of work - a service for clients
public interface IUnitOfWork : IDisposable
{
IAnimalRepository AnimalRepository { get; }
IHumanRepository HumanRepository { get; }
// .. other repositories follow
void SaveChanges();
}
通过这种方式,您的服务层依赖于存储库层,并且您可以轻松地在实现之间切换,例如单元测试。您的客户编写
// example code
using ( IUnitOfWork uow = new YourImplementationOfUnitOfWork() )
{
var animals = uow.AnimalRepository.FindByNumberOfLegs( 3 );
var person = uow.HumanRepository.CreateNew();
person.Name = "John";
uow.HumanRepository.Insert( person );
uow.SaveChanges();
}
如果您计划限制方法的数量,您只需稍微修改存储库接口:
// shared between repositories
public interface IGenericRepository<T>
{
T CreateNew();
void Delete( T item );
void Update( T item );
void Insert( T item );
IQueryable<T> Query { get; }
}
通过这种方式,您的客户可以使用LINQ:
// example code
using ( IUnitOfWork uow = new YourImplementationOfUnitOfWork() )
{
var animals = uow.AnimalRepository.Query.Where( a => a.NumberOfLegs == 3 );
var person = uow.HumanRepository.CreateNew();
person.Name = "John";
uow.HumanRepository.Insert( person );
uow.SaveChanges();
}
我可以建议应用接口隔离原则吗?即将您的接口分成逻辑组。这也将允许界面的用户不实现他们不使用/不需要的部分。稳定性也应该提高,因为您将拥有更谨慎的可测试代码。