0

Java 或 dotNet 世界有丰富的开源框架和库。我们几乎在任何地方都喜欢使用 Spring 和 Hibernate。每个人都同意hibernate是一个非常方便的工具。Hibernate 可以做什么?好吧,基本上 - Hibernate 可以跟踪我们的域对象更改并仅将修改后的数据保存到数据库中,就是这样。基本上,这就是我们想要的一切。我想从数据库中加载一些记录,对它们进行一些修改,然后调用 transaction.commit(),所有修改都会立即持久化。那太好了,对吧!

但是网络世界呢?在 Web 应用程序中,数据库会话必须关闭。我无法加载一些域对象并等待用户通过 HTTP 进行修改,并在修改后保留这些对象。

我们必须使用分离的对象或 DTO。这个怎么运作 ?用户在 HTML 浏览器中进行修改,spring Mvc 使用 MVC 模型绑定自动将这些 HTML 修改传递给我们自定义的 DTO 对象,然后我们进行一些编程工作以将修改从 DTO 对象传递到休眠域对象,然后我们才将它们持久化。例如 - 我们有一个更新客户地址的 Web 表单,以及另一个更新客户详细信息的表单。我们必须有两个不同的业务层方法——UpdateAddress() 和UpdateDetails(),这两个方法都必须接受某种DTO,一个代表地址信息,另一个代表细节信息。我们还有自定义逻辑,将数据从这 2 个 DTO 传输到域类“客户”。是的,当然,我们可以重用我们的域类,而不是 DTO 对象。但这并没有让它变得更简单。在这两种情况下,我们仍然必须实现将修改转移到持久对象的自定义逻辑,我不能立即持久化分离的对象,因为通常域类有很多很多属性代表许多关系,例如。客户有 - Orders 属性。当我更新客户地址时,我不想更新其订单。

是否有一种美观通用的方法可以将修改从 mvc 模型映射到域对象,而无需编写大量自定义代码并且没有覆盖太多字段的风险?

4

1 回答 1

0

拥有一个数据访问层是一个很好的做法,这意味着为每个域对象/实体都有一个存储库。此外,所有存储库都共享公共代码,因此您自然拥有一个抽象存储库:

public abstract class AbstractRepository<E extends BaseModel> implements Repository<E> {

    @PersistenceContext
    private EntityManager entityManager;

    private Class<E> entityClass;

    public AbstractRepository(Class<E> entityClass) {
        this.entityClass = entityClass;
    }

    protected EntityManager getEM() {
        return entityManager;
    }

    protected TypedQuery<E> createQuery(String jpql) {
        return createQuery(jpql, entityClass);
    }

    protected <T> TypedQuery<T> createQuery(String jpql, Class<T> typeClass) {
        return getEM().createQuery(jpql, typeClass);
    }

    @Override
    public E merge(E entity) {
        return getEM().merge(entity);
    }

    @Override
    public void remove(E entity) {
        getEM().remove(entity);
    }

    @Override
    public E findById(long id) {
        return getEM().find(entityClass, id);
    }
} 

拥有一个服务层也是一种很好的做法,您可以在其中创建、更新和删除实体的实例(如果您愿意,可以通过 DTO 传递到 create 和 update 方法)。

...

@Inject
private CustomerRepository customerRepository;

public Customer createCustomer(CustomerDto customerDto) {
    Customer customer = new Customer();
    customer.setEmail(customerDto.getEmail());
    ...
    return customerRepository.merge(customer); 
}

public Customer updateCustomerAddress(Customer customer, String address) {
    customer.setAddress(address);
    return customerRepository.merge(customer);  
}
...

所以这取决于你想要多少更新方法。我通常会将它们分组到常见的操作中,例如更新客户的地址,您可以将客户 ID 和更新的地址从前端(可能通过 ajax)传递到在特定端点上侦听的控制器。例如,您可以在此端点使用存储库通过 Id 查找实体,然后将其传递给您的服务以进行地址更新。

最后,您需要确保数据实际得到持久化,因此在 Spring 中,您可以将@Transactional注释添加到 Spring MVC 控制器或执行持久化的服务。我不知道这方面的任何最佳实践,但我更喜欢将其添加到我的控制器中,这样无论您使用什么服务,您都可以始终保证进行交易。

于 2013-07-06T09:09:34.687 回答