将实体保存到数据库中的设计模式

Iva*_*kin 6 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我主要担心的是上面的代码违反了 SOLID 原则,因为它负责创建和删除自己。

也许这些 Save 和 Delete 方法应该放在 Product 实体之外的某个地方(也许是 Factory/Repository?)。

jan*_*ann 1

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

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

public class Product : IEntity {
    public int ID { get; set; }
    public string Name { get; set; }
    public double Price { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

接下来,我将创建一个命令和查询接口来使用该实体:

public interface ICommand {} // Marker interface

public interface IQuery<TResult> {} // Marker interface
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

现在您对写入(命令)和读取(查询)端有了清晰的指示和分离。

这意味着我们可以创建一个命令及其处理程序来保存您的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);
    }
}
Run Code Online (Sandbox Code Playgroud)

在上面,我们定义了一个用于处理此实体的存储库,但是您可以直接依赖于此处的数据库上下文并对它执行查询/命令,或者您可以使用单独的产品存储库或仅使用单独的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
    }
}
Run Code Online (Sandbox Code Playgroud)

您永远不应该将 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;
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这是用记事本编写的,可能无法 100% 编译,但您应该了解如何分离各个组件,以便遵循 SOLID。:-)