[英]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.