请设计一个仓库模式的实现方案,该方案需要支持数据的软删除和版本控制,以适应更加复杂的业务需求。

仓库模式实现方案:支持软删除和版本控制

1. 概述

在领域驱动设计(DDD)中,仓库模式(Repository Pattern)用于处理数据的持久化问题。为了适应更加复杂的业务需求,如支持数据的软删除和版本控制,需要对传统的仓库模式进行扩展。本文档将介绍如何设计一个支持这些功能的仓库模式。

2. 设计思路

2.1 软删除

软删除的概念指的是数据在逻辑上被删除,但在物理上仍然存在于数据库中。这可以通过在数据库表中添加一个标记字段(例如 is_deleteddeleted_at)来实现。当一个记录被“删除”时,实际上只是更新了这个标记字段。

2.2 版本控制

版本控制的目的是记录数据的变更历史,以便在需要时能够恢复到某个特定的版本。这可以通过在数据库表中添加版本号字段(例如 version)和时间戳字段(例如 updated_at)来实现。每当数据发生变化时,版本号递增,并记录更改的时间。

3. 数据库设计

3.1 实体表设计

假设我们有一个 Product 实体,其表结构如下:

CREATE TABLE `products` (
  `id` INT AUTO_INCREMENT PRIMARY KEY,
  `name` VARCHAR(255) NOT NULL,
  `description` TEXT,
  `price` DECIMAL(10, 2) NOT NULL,
  `is_deleted` BOOLEAN DEFAULT FALSE,
  `deleted_at` TIMESTAMP NULL,
  `version` INT DEFAULT 0,
  `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
  • is_deleted:布尔值,表示该记录是否已删除(逻辑删除)。
  • deleted_at:时间戳,记录删除的时间。
  • version:整数,记录数据的版本号。
  • updated_at:时间戳,记录上次更新的时间。

3.2 版本历史表设计

为了记录每个版本的变更历史,我们可以创建一个 ProductHistory 表:

CREATE TABLE `product_history` (
  `id` INT AUTO_INCREMENT PRIMARY KEY,
  `product_id` INT NOT NULL,
  `name` VARCHAR(255) NOT NULL,
  `description` TEXT,
  `price` DECIMAL(10, 2) NOT NULL,
  `version` INT NOT NULL,
  `updated_at` TIMESTAMP NOT NULL,
  FOREIGN KEY (`product_id`) REFERENCES `products` (`id`)
);
  • product_id:外键,关联 products 表的 id
  • version:记录该版本号。
  • updated_at:记录该版本的更新时间。

4. 仓库类设计

4.1 仓库接口

定义一个仓库接口 IProductRepository,包含基本的 CRUD 操作和扩展的功能:

public interface IProductRepository {
    Product get(int id);
    List<Product> getAll();
    void add(Product product);
    void update(Product product);
    void delete(int id);
    List<ProductHistory> getHistory(int id);
    ProductHistory getHistoryByVersion(int id, int version);
}

4.2 仓库实现

实现上述接口,实现类 ProductRepository

public class ProductRepository implements IProductRepository {
    private final EntityManager entityManager;

    public ProductRepository(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Override
    public Product get(int id) {
        return entityManager.find(Product.class, id);
    }

    @Override
    public List<Product> getAll() {
        String jpql = "SELECT p FROM Product p WHERE p.isDeleted = false";
        return entityManager.createQuery(jpql, Product.class).getResultList();
    }

    @Override
    public void add(Product product) {
        entityManager.persist(product);
    }

    @Override
    public void update(Product product) {
        Product existingProduct = get(product.getId());
        if (existingProduct != null) {
            // 记录版本历史
            ProductHistory history = new ProductHistory(existingProduct);
            entityManager.persist(history);

            // 更新版本号
            product.setVersion(existingProduct.getVersion() + 1);
            product.setUpdatedAt(new Timestamp(System.currentTimeMillis()));
            entityManager.merge(product);
        }
    }

    @Override
    public void delete(int id) {
        Product product = get(id);
        if (product != null) {
            product.setIsDeleted(true);
            product.setDeletedAt(new Timestamp(System.currentTimeMillis()));
            entityManager.merge(product);
        }
    }

    @Override
    public List<ProductHistory> getHistory(int id) {
        String jpql = "SELECT h FROM ProductHistory h WHERE h.productId = :id";
        return entityManager.createQuery(jpql, ProductHistory.class)
                .setParameter("id", id)
                .getResultList();
    }

    @Override
    public ProductHistory getHistoryByVersion(int id, int version) {
        String jpql = "SELECT h FROM ProductHistory h WHERE h.productId = :id AND h.version = :version";
        return entityManager.createQuery(jpql, ProductHistory.class)
                .setParameter("id", id)
                .setParameter("version", version)
                .getSingleResult();
    }
}

5. 服务层设计

服务层负责处理业务逻辑,调用仓库层的方法。这里以 ProductService 为例:

public class ProductService {
    private final IProductRepository productRepository;

    public ProductService(IProductRepository productRepository) {
        this.productRepository = productRepository;
    }

    public Product getProduct(int id) {
        return productRepository.get(id);
    }

    public List<Product> getAllProducts() {
        return productRepository.getAll();
    }

    public void addProduct(Product product) {
        productRepository.add(product);
    }

    public void updateProduct(Product product) {
        productRepository.update(product);
    }

    public void deleteProduct(int id) {
        productRepository.delete(id);
    }

    public List<ProductHistory> getProductHistory(int id) {
        return productRepository.getHistory(id);
    }

    public ProductHistory getProductHistoryByVersion(int id, int version) {
        return productRepository.getHistoryByVersion(id, version);
    }
}

6. 总结

通过上述设计,我们实现了一个支持软删除和版本控制的仓库模式。这样不仅能够满足复杂业务需求,还提高了系统的可维护性和可扩展性。