代码之家  ›  专栏  ›  技术社区  ›  Jakob

JpaRepository与不同表上的Native@Query

  •  0
  • Jakob  · 技术社区  · 6 年前

    我只是在spring数据中偶然发现了一些意想不到的行为。 为了演示我用initializer设置了一些spring引导应用程序( https://start.spring.io/ )添加JPA、Web、H2。

    应用程序包含两个表和一些数据:

    数据.sql:

    create table table1 (
      id int,
      name varchar(50)
    );
    
    create table table2 (
      id int,
      name varchar(50)
    );
    
    insert into table1 (id, name) values (1, 'First row from table 1');
    insert into table1 (id, name) values (2, 'Second row from table 1');
    insert into table1 (id, name) values (3, 'Third row from table 1');
    insert into table1 (id, name) values (4, 'Fourth row from table 1');
    
    insert into table2 (id, name) values (1, '** TABLE 2: 1st ROW UPPERCASE **');
    insert into table2 (id, name) values (2, '** TABLE 2: 2nd ROW UPPERCASE **');
    

    此表结构只有一个模型,因为两个表的结构相同。我为这个表创建了一个JpaRepository

    @Repository
    public interface SampleDAO extends JpaRepository<SampleModel, Integer> {
    
      @Query(value = "select id, name from table1", nativeQuery = true)
      List<SampleModel> findAllFromTable1();
    
      @Query(value = "select id, name from table2", nativeQuery = true)
      List<SampleModel> findAllFromTable2();
    }
    

    最后我添加了一个控制器(TestController):

    @RestController
    public class TestController {
    
      @Autowired
      private final SampleDAO sampleDAO;
    
      public TestController(SampleDAO sampleDAO) {
        this.sampleDAO = sampleDAO;
      }
    
      @GetMapping(path = "/")
      @ResponseBody
      public String testNativeQuery() {
        List<SampleModel> list1 = this.sampleDAO.findAllFromTable1();
        List<SampleModel> list2 = this.sampleDAO.findAllFromTable2();
    
        SampleModel m1 = list1.get(0);
        SampleModel m2 = list2.get(0);
        System.out.println("*****************************************");
        System.out.println("Data from findAllFromTable1():");
        list1.forEach(l -> {
          System.out.println(l.getName());
        });
        System.out.println("*****************************************");
        System.out.println("Data from findAllFromTable2():");
        list2.forEach(l -> {
          System.out.println(l.getName());
        });
        System.out.println("*****************************************");
    
        return "Done";
      }
    }
    

    我希望list1和list2包含我的两个表的数据,但令人惊讶的是,只获取了第一个表的结果:

    *****************************************
    Data from findAllFromTable1():
    First row from table 1
    Second row from table 1
    Third row from table 1
    Fourth row from table 1
    *****************************************
    Data from findAllFromTable2():
    First row from table 1
    Second row from table 1
    *****************************************
    

    https://github.com/steinmann321/nativequerydemo

    这是预期的行为还是我做错了什么?

    (请注意:这只是一个示例项目,实际查询要复杂得多,但结果是相同的)

    1 回复  |  直到 6 年前
        1
  •  3
  •   M. Rizzo    6 年前

    您在持久实体之间的身份冲突方面遇到了问题。您可以看到,您从第一个查询中得到四条记录,从第二个查询中得到两条与数据库中的记录匹配的记录。但是当entitymanager正在处理第二个集合中的记录时,它看到已经有ID为1和2的持久实体,因此它不会创建新的实体。

    创建JPA可嵌入密钥:

    @Embeddable
    public class MyKey implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        @Column(name = "id", nullable = false)
        private String id;
    
        @Column(name = "name", nullable = false)
        private String name;
    
        public String getId() {
          return id;
        }
    
        public void setId(String id) {
          this.id = id;
        }
    
        public String getName() {
          return name;
        }
    
        public void setName(String name) {
          this.name = name;
        }
    
        @Override
        public boolean equals(Object o) {
          if (this == o) {
            return true;
          }
          if (o == null || getClass() != o.getClass()) {
            return false;
          }
          MyKey that = (MyKey) o;
          return Objects.equals(id, that.getId()) && Objects.equals(name, that.getName());
        }
    
        @Override
        public int hashCode() {
          return Objects.hash(id, name);
        }
    }   
    

    然后使用SampleModel实体中的嵌入键:

    @Entity
    public class SampleModel {
    
      @EmbeddedId
      private MyKey myKey;
    
      public MyKey getMyKey() {
        return myKey;
      }
    
      public void setMyKey(MyKey myKey) {
        this.myKey = myKey;
      }
    }
    

    System.out.println("*****************************************");
    System.out.println("Data from findAllFromTable1():");
    list1.forEach(l -> {
      System.out.println(l.getMyKey().getName());
    });
    System.out.println("*****************************************");
    System.out.println("Data from findAllFromTable2():");
    list2.forEach(l -> {
      System.out.println(l.getMyKey().getName());
    });
    System.out.println("*****************************************");
    

    然后试试你的TestController。我试过了,结果是:

    *****************************************
    Data from findAllFromTable1():
    First row from table 1
    Second row from table 1
    Third row from table 1
    Fourth row from table 1
    *****************************************
    Data from findAllFromTable2():
    ** TABLE 2: 1st ROW UPPERCASE **
    ** TABLE 2: 2nd ROW UPPERCASE **
    *****************************************
    
    推荐文章