[英]Design pattern for saving entities into database
我有一个类似于下面的类(C#):
public class Product {
public int ID {get;set;}
public string Name {get;set;}
public double Price {get;set;}
public void Save() {
string sql = "INSERT INTO Product.....";
Database.Execute(sql);
}
public void Delete() {
string sql = "DELETE Product WHERE.....";
Database.Execute(sql);
}
}
我主要担心的是上面的代码违反了SOLID原则,因为它负责创建和删除自身。
也许这些Save和Delete方法应该放在Product实体之外的某个地方(Factory / Repository可能?)。
我相信Facade模式在你的情况下会做得很好。 Facade模式也称为服务层。
在你的情况下,你基本上会有一个服务(一个类),它将拥有你需要的所有方法。 您的服务应该是这样的。
class ProductService
{
public void Save(Product product)
{
// SAVE THE PRODUCT
}
public void Delete(Product product)
{
// DELETE PRODUCT
}
}
您希望将类注入要保存或删除产品的位置。 这样,您所要做的所有工作都将在一个单独的类中,您的代码将变得更加清晰。 让所有这些在存储过程中插入和删除statemenet也是一个好主意。
我将介绍您的模型实体,命令和查询模式以及数据库层或存储库。
您的模型是您的Product
,此对象应该是一个普通对象:
public class Product : IEntity {
public int ID { get; set; }
public string Name { get; set; }
public double Price { get; set; }
}
接下来,我将创建一个用于处理此实体的命令和查询接口:
public interface ICommand {} // Marker interface
public interface IQuery<TResult> {} // Marker interface
接下来为ICommand
和IQuery
定义处理程序:
public interface IHandleQuery<TQuery, TResult> where TQuery : IQuery<TResult>
{
TResult Handle(TQuery query);
}
public interface IHandleCommand<TCommand> where TCommand : ICommand
{
void Handle(TCommand command);
}
现在,您可以清楚地指出并分离您的写入(命令)和读取(查询)方面。
这意味着我们可以创建一个命令及其处理程序来保存您的Product
如:
public class SaveProduct : ICommand
{
public string Name { get; private set; }
public double Price { get; private set; }
public SaveProduct(string name, double price)
{
Name = name;
Price = price;
}
}
public class HandleSaveProduct : IHandleCommand<SaveProduct>
{
private readonly IRepository<Product> _productRepository;
public HandleSaveProduct(IRepository<Product> productRepository)
{
_productRepository = productRepository;
}
public void Handle(SaveProduct command)
{
var product = new Product {
Name = command.Name,
Price = command.Price
};
_productRepository.Save(product);
}
}
在上面我们已经定义了一个用于处理这个实体的存储库,但是你可以在这里直接依赖你的数据库上下文并对它执行查询/命令,或者你可以使用
GenericRepository<TEntity> : IRepository<TEntity>
来实现存储库模式。只是单独的产品库:
public interface IEntity { } // Marker interface
public interface IRepository<TEntity> where TEntity : IEntity
{
TEntity Get(object primaryKey);
void Save(TEntity entity); // should handle both new and updating entities
void Delete(TEntity entity);
}
public class ProductRepository : IRepository<Product>
{
public Product Get(object primaryKey)
{
// Database method for getting Product
}
public void Save(Product entity)
{
// Database method for saving Product
}
public void Delete(Product entity)
{
// Database method for deleting Product
}
}
您永远不应该将您的Product实体返回到您的UI,而是使用视图模型,例如:
public class ProductViewModel {
public int ID { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public DateTime Whatever { get; set; }
}
public class GetProductById : IQuery<ProductViewModel>
{
public int Id { get; private set; }
public GetProductById(int id)
{
Id = id;
}
}
public class HandleGetProductById : IHandleQuery<GetProductById, ProductViewModel>
{
private readonly IRepository<Product> _productRepository;
public HandleGetProductById(IRepository<Product> productRepository)
{
_productRepository = productRepository;
}
public ProductViewModel Handle(GetProductById query)
{
var product = _productRepository.Get(query.Id);
return product.Select(x => new ProductViewModel {
Name = x.Name,
Price = x.Price;
});
}
}
请注意这是用记事本写的,可能无法100%编译,但你应该知道如何分离各种组件以便遵循SOLID。 :-)
你似乎想要某种类似Repository的存储库 。 你已经在[问题]中提到了它。 该链接仅供参考 - 我不建议您实施。 为什么?
因为像@Igor说的那样,如果你使用的是ORM,那么你将免费获得这份合同。 例如,NHibernate有一个带有Query<T>()
, Save()
, Delete()
等方法的ISession
。 这就是你所需要的。
我使用的几乎所有项目都使用了这种“基础设施”ORM合同的抽象(服务/存储库/等),所谓的抽象很弱,只能创造更多的代码来维持和更高的技术债务和错误。
采取务实的方法:
GetTop15TransactionsWithoutFeesExcludingCreditsGroupByDayRecentAtTop()
任何人?),您不需要查询对象或Repository方法。 HTH。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.