c# - 将实体保存到数据库的设计模式

标签 c# design-patterns solid-principles

我有一个类似于下面的类(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?)。

最佳答案

我将介绍您的模型实体、命令和查询模式以及数据库层或存储库。

你的模型就是你的Product这个对象应该是一个普通对象:

public class Product : IEntity {
    public int ID { get; set; }
    public string Name { get; set; }
    public double Price { get; set; }
}

接下来我将创建一个命令和查询接口(interface)来处理这个实体:

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);
    }
}

In the above we have defined an repository for handling this entity, you can however depend directly on your database context here and do the queries/commands to it or you can implement the repository pattern using an GenericRepository<TEntity> : IRepository<TEntity> or just the separate product repository:

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
    }
}

你不应该将你的产品实体返回到你的用户界面,而是使用 View 模型,例如:

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。 :-)

关于c# - 将实体保存到数据库的设计模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36899101/

相关文章:

c# - 连接到 Oracle 服务器时找不到文件 'C:\SomePath\Oracle.DataAccess.Common.Configuration.Section.xsd'

c# - UWP、MySQL、填充ListView、实现CRUD操作

asp.net-mvc - 您如何设计需要为每个新客户定制的Web应用程序?

c# - WPF 切角元素

c# - WPF 中的 float 项目

java - 浏览器在页面重新加载时要求重新发送数据

c++ - Meyers 的 Singleton 模式线程安全实现吗?

oop - 省略 super() 和/或 *weakening* 前提条件是否违反里氏替换原则?

java - 空对象模式是否违反了接口(interface)隔离原则?

java - 实现依赖注入(inject)设计模式