DAO方法参数,对象引用vs ids

时间:2015-01-28 14:26:47

标签: java hibernate jpa repository dao

问题

dao / repository方法,实体对象或entity-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()或lock,请参阅getProductsOf2()和getProductsOf3()。
  • 即使您知道卖家的ID,您首先必须分别查询卖家对象。 (load()可以用来代替使用代理来避免对卖方的额外查询,但你仍然需要调用会话对象。)
  • 参数可以为null。

优点:getProductsOf(long sellerId)

  • 如果您还没有卖家对象,但知道卖家ID,那么当您只需要在工作单元中查询卖家ID时,这可能会更快。
  • 避免空引用问题

缺点:getProductsOf(long sellerId)

  • 当方法中存在多个“long”参数时,您可能会在参数调用顺序中出错,导致您使用错误的ID进行查询。
  • 比使用对象作为参数更像是一种面向对象的方法。
  • 方法调用看起来不太干净:
    getProductsOf(seller.getId())
    而不是:
    getProductsOf(seller)

我的偏好

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

2 个答案:

答案 0 :(得分:2)

最好的方法是避免写下自己的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方法采用实体
  • findOne和exists采用标识符,因为它假设您没有要获取的实体

对于findOne,最好让它采用标识符。这样即使您有实体也可以调用它。如果它是一个实体,那么你必须创建一个带有填充标识符的瞬态实体,只是为了获取相关的管理实体。

答案 1 :(得分:1)

为什么不同时使用它们?

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

public List<Product> getProductsOf(Seller seller){
    return getProductsOf(seller.getId());
}

另外,我更喜欢使用类而不是本机类型来表示id,因为这样你可以验证对象是否是新的(seller.getId()== null)并调用persist()或merge()