问题

dao/存储库方法的参数类型,实体对象或实体ID的最佳实践是什么?

范例程式码

@Entity
class Product {
    // ...

    @ManyToOne
    Seller seller;
}

@Entity
class Seller {
    @Id @GeneratedValue
    Long id;
}

class ProductDao {
    // ...

    // Using ids
    public List<Product> getProductsOf(long sellerId) {
        return getSession()
            .createQuery("from Product where seller.id = ?")
            .setLong(0, sellerId)
            .list();
    }

    // Using object-references
    public List<Product> getProductsOf(Seller seller) {
        return getSession()
            .createQuery("from Product where seller = ?")
            .setEntity(0, seller)
            .list();
    }

    // Using object-references using merge() on a detached object
    public List<Product> getProductsOf2(Seller seller) {
        Seller persistentSeller = getSession().merge(seller);

        return getSession()
            .createQuery("from Product where seller = ?")
            .setEntity(0, seller)
            .list();
    }

    // Using object-references using lock() on a detached object
    public List<Product> getProductsOf3(Seller seller) {
        getSession().buildLockRequest(LockOptions.NONE).lock(seller);

        return getSession()
            .createQuery("from Product where seller = ?")
            .setEntity(0, seller)
            .list();
    }
}

利弊

我发现了以下优点和缺点,但是我想知道在经验丰富的Spring/Hibernate/JPA用户中是否存在最佳实践。

优点:getProductsOf(卖方)
  • 如果您已经拥有处于持久上下文(持久状态)中的卖方,则从客户角度易于使用。

  • 缺点:getProductsOf(卖方卖方)
  • 您必须验证卖方处于持久或分离状态,这可能会使其实现变得冗长。您必须使用merge()或锁定,请参见getProductsOf2()和getProductsOf3()。
  • 即使您知道卖方的ID,也必须首先分别查询卖方对象。 (可以使用load()代替使用代理,以避免对卖方进行额外查询,但是您仍然必须调用 session 对象。)
  • 参数可以为null。

  • 优点:getProductsOf(long SellerId)
  • 如果您还没有卖方对象,但是知道了SellerId,那么当您只需要在工作单元中查询一次SellerId时,这可能会更快。
  • 避免了空引用问题

  • 缺点:getProductsOf(long SellerId)
  • 当方法中存在多个“长”参数时,您可能会误认为参数调用顺序,从而导致使用错误的ID进行查询。
  • 与使用对象作为参数相比,感觉不太像面向对象的方法。
  • 方法调用看起来不太干净:getProductsOf(seller.getId())代替:getProductsOf(seller)

  • 我的喜好

    我正在使用getProductsOf(Seller seller),但是必须验证卖方是处于持久状态还是分离状态非常麻烦。因此,我正在考虑使用id代替。

    最佳答案

    最好的方法是避免写下您自己的DAO,而改用Spring Data

    我更喜欢Spring Repository API,它看起来像这样:

    public interface CrudRepository<T, ID extends Serializable>
        extends Repository<T, ID> {
        <S extends T> S save(S entity);
    
        T findOne(ID primaryKey);
    
        Iterable<T> findAll();
    
        Long count();
    
        void delete(T entity);
    
        boolean exists(ID primaryKey);
    
    }
    
  • savedelete方法采用实体
  • findOneexists采用标识符,因为它假定您没有要获取的实体

  • 至于findOne,最好让它带有一个标识符。这样,即使您有实体,也可以调用它。如果它是一个实体,那么仅为了获取关联的受管实体,就必须创建一个具有填充标识符的临时实体。

    关于java - DAO方法参数,对象引用与ID,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28194683/

    10-09 05:25