JPA:所有实体一个 DAO,还是每个实体一个 DAO?

Posted

技术标签:

【中文标题】JPA:所有实体一个 DAO,还是每个实体一个 DAO?【英文标题】:JPA: one DAO for all the entities or one for each entity? 【发布时间】:2014-09-02 03:02:52 【问题描述】:

首先,对不起我的英语。

我正在为朋友制作一个使用 JPA(EclipseLink) 访问 SQLite 数据库的桌面应用程序。

我已经在 Eclipse 中创建了数据库和实体。但我还创建了一个名为 UniversalDAO 的类,它是所有实体用来访问和持久化数据库的实用程序类:

package model.DAO;

import java.util.ArrayList;

import javax.persistence.*;

import model.entities.Entities;


public class UniversalDAO 


    private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("TheDatabase");
    private static EntityManager em = emf.createEntityManager();

    private UniversalDAO ()


    public static void close()
        em.close();
        emf.close();
    

    public static Entities getOne(Class<? extends Entities> table, Object primaryKey) 

        return em.find(table, primaryKey);
    

    public static ArrayList<Entities> getAll(Class<? extends Entities> table) 

        ArrayList<Entities> ret = new ArrayList<>();

        for(Object obj : em.createQuery("SELECT o FROM " + table.getName() + " o").getResultList())
            ret.add((Entities) obj);

        return ret;
    

    public static ArrayList<Entities> getWithCondition(Class<? extends Entities> table, String condition) 

        ArrayList<Entities> ret = new ArrayList<>();

        for(Object obj : em.createQuery("SELECT o FROM " + table.getName() + " o WHERE " + condition).getResultList())
            ret.add((Entities) obj);

        return ret;
    

    public static void insert(Entities row) 
        em.getTransaction().begin();

        em.persist(row);

        em.flush();

        em.getTransaction().commit();
    

    public static void update(Entities row) 

        em.getTransaction().begin();

        em.merge(row);

        em.flush();

        em.getTransaction().commit();
    

    public static void delete(Class<? extends Entities> table, Object primaryKey) 

        em.getTransaction().begin();

        Entities row = em.find(table, primaryKey);

        em.remove(row);

        em.flush();

        em.getTransaction().commit();
    

为了对所有实体进行分组并在此类中使用它们,我创建了一个名为 Entities 的空接口。

这是其中一个实体的样子:

package model.entities;

import java.util.ArrayList;

import javax.persistence.*;


@Entity
@Table(name="emails")
public class EntityEmail implements Entities 

    @Id
    @Column(name="id_email")
    @GeneratedValue(strategy=GenerationType.SEQUENCE)
    private int idEmail;

    @Column(name="email")
    private String email;

    @Column(name="description")
    private String description;

    @ManyToMany(fetch=FetchType.EAGER)
    @JoinTable(name="people_emails",
               joinColumns=@JoinColumn(name="id_email", referencedColumnName="id_email"),
               inverseJoinColumns=@JoinColumn(name="id_person", referencedColumnName="id_person"))
    private ArrayList<EntityPerson> people;

    public EntityEmail() 

       

    public int getIdEmail() 
        return this.idEmail;
    
    public void setIdEmail(int idEmail) 
        this.idEmail = idEmail;
       

    public String getEmail() 
        return this.email;
    
    public void setEmail(String email) 
        this.email = email;
    

    public String getDescription() 
        return description;
    
    public void setDescription(String description) 
        this.description = description;
    

    public ArrayList<EntityPerson> getPeople() 
        return people;
    
    public void setPeople(ArrayList<EntityPerson> people) 
        this.people = people;
       

就像您可以欣赏我不是专业人士一样,我还有很多东西要学。 所以,我想知道这种方法是否正确,或者我是否应该为每个实体设置一个 DAO。

【问题讨论】:

您可能想阅读tutorialspoint.com/design_pattern/… 【参考方案1】:

您似乎在尝试发明通用 DAO 模式。如果是这样,那么您基本上是在正确的道路上。

通用 DAO 模式的工作原理如下:

创建一个所有 DAO 都将扩展的通用基类:

public abstract class GenericDao<E, ID extends Serializable> 
    ...
    // Implement common operations that are relevant to all entities here:
    public E findById(ID id)  ... 
    public void save(E entity)  ... 
    // etc
    ...

通过扩展 GenericDao 创建具体的 DAO 实现:

public class EntityEmailDao extends GenericDao<EntityEmail, Integer> 
    // This class may contain operations that are relevant to specific entity:
    public E findByEmail(String email)  ... 

由于GenericDao 是通用的,您不需要让您的实体扩展任何通用接口

这种模式有很多现有的实现,看看,例如,here。

【讨论】:

我喜欢这个主意。由于我所有的实体都会做几乎相同的事情,重复的道类是不好的。拥有一个抽象类,然后每个实体都有一个类来扩展该抽象类,这是正确的做法。每一道都有共同的行为和特定的行为。我会这样做的,非常感谢;)

以上是关于JPA:所有实体一个 DAO,还是每个实体一个 DAO?的主要内容,如果未能解决你的问题,请参考以下文章

java web spring jpa 在以接口为dao的方法里使用原生sql,联合查找没有对应实体,用啥来接收? 求大神

取消引用的休眠 (JPA) 实体会发生啥情况?

处理来自 JPA/DAO 实体的结果中的非 DB 映射字段

Spring Boot-------JPA——EntityManager构建通用DAO

将分离的实体合并到 JPA 中的实体管理器的最佳方法是啥

JPA:返回多个实体的查询