【问题标题】:DAO methods parameters , object-references vs idsDAO 方法参数,对象引用 vs id
【发布时间】:2015-03-27 11:54:51
【问题描述】:

问题

dao/repository 方法、实体对象或实体 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(Seller Seller)

  • 当您已经有一个处于持久上下文(持久状态)的卖家时,从客户的角度来看很容易使用。

缺点:getProductsOf(Seller Seller)

  • 您必须验证卖方是否处于持久或分离状态,这会使其实施变得冗长。您必须使用 merge() 或锁定,请参阅 getProductsOf2() 和 getProductsOf3()。
  • 即使知道卖家的id,​​也得先单独查询卖家对象。 (load() 可用于使用代理来避免对卖方的额外查询,但您仍然必须调用会话对象。)
  • 参数可以为空。

优点:getProductsOf(long SellerId)

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

缺点:getProductsOf(long SellerId)

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

我的偏好

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

【问题讨论】:

  • 我会说这取决于。如果您只想要一个对象的 id,则无需创建整个对象引用来设置 id 并将其作为参数传递。另一方面,如果您需要传递多个参数,请使用适当的对象引用。
  • 当方法中存在多个“long”参数时,你可能会弄错参数调用顺序,导致你使用错误的id进行查询如果你遇到这种情况,我会说你的设计有问题。

标签: java hibernate jpa repository dao


【解决方案1】:

最好的方法是避免写下你自己的 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,最好是带一个标识符。这样,即使您有实体,您也可以调用它。如果它是一个实体,那么您必须创建一个带有填充标识符的临时实体,只是为了获取关联的托管实体。

【讨论】:

  • 这些是基本的 crud 操作,而不是 OneToMany/ManyToOne 等上的操作。这个问题并不真正适用于 crud 操作。此外,在某些时候,您想编写自己的自定义查询方法。在 Spring Data 文档中,他们使用:User findByEmailAddress(EmailAddress emailAddress); ,这表明他们更喜欢对象引用而不是 id,但 emailAddress 可能是一个值类型,所以不清楚 Spring 开发人员更喜欢什么。
【解决方案2】:

为什么不同时拥有它们?

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() .

【讨论】:

    猜你喜欢
    • 2020-08-04
    • 1970-01-01
    • 1970-01-01
    • 2016-09-29
    • 1970-01-01
    • 1970-01-01
    • 2018-08-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多