DAO在一种方法中更新数据库,但在其他方法中没有

时间:2014-06-09 08:53:57

标签: java spring hibernate jpa

我有一个DAO,其实现使用JPA实体管理器,以及spring @Transactional。我有一个addOrUpdate方法,它将新实体持久保存到数据库或更新现有实体,这似乎工作正常。我有另一种名为removeById的方法,它实际上并没有从数据库中删除实体,但只能通过将其状态设置为非活动状态('I')来使其无效。但是,在调用removeById时,不会对数据库进行任何更新。为什么呢?

这是DAO:

@Repository
@Transactional
public class ClientDaoImpl implements ClientDao {   

    @PersistenceContext
    EntityManager entityManager;

    @Autowired
    LocationDao locationDao;

    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<ClientDTO> findAll() {

        List<Client> clientsDb = entityManager.createQuery(
                "from Client c where c.state = 'A'").getResultList();

        List<ClientDTO> clients = null;

        if (clientsDb != null) {
            clients = new ArrayList<>();
            for (Client client : clientsDb) {
                clients.add(ClientDTO.entityToDto(client));
            }
        }

        return clients;
    }

    @Override
    public ClientDTO findById(long id) {
        Client clientDb = entityManager.find(Client.class, id);
        ClientDTO client = null;
        if (clientDb != null) {
            client = ClientDTO.entityToDto(clientDb);
        }
        return client;
    }

    @Override
    public ClientDTO addOrUpdate(ClientDTO dto) {

        Client clientDb = null;
        if (dto.getId() == 0) {
            clientDb = new Client();
            clientDb.setLocation(new ArrayList<Location>());
            clientDb.setState('A');
        } else {
            clientDb = entityManager.find(Client.class, dto.getId());
            if (clientDb == null) {
                throw new EntityNotFoundException("Client Entity with id "
                        + dto.getId() + " could not be found!");
            }
        }

        clientDb.setName(dto.getName());
        clientDb.setAddress(dto.getAddress());
        clientDb.setCode(dto.getCode());
        clientDb.setOib(dto.getOib());
        clientDb.setExternId(dto.getExternId());
        clientDb.setDateFrom(dto.getDateFrom());
        clientDb.setDateTo(dto.getDateTo());

        clientDb.getLocation().clear();

        for (LocationDTO locationDto : dto.getLocation()) {

            locationDto = locationDao.addOrUpdate(locationDto);         

            Location locationDb = entityManager.find(Location.class,
                    locationDto.getId());

            if (locationDb == null) {
                throw new EntityNotFoundException("Location Entity with id "
                        + locationDto.getId() + " could not be found!");
            }                               

            clientDb.getLocation().add(locationDb);

        }

        if (clientDb.getId() == 0) {
            entityManager.persist(clientDb);
        }

        return ClientDTO.entityToDto(clientDb);
    }

    @Override
    public void remove(ClientDTO entity) {
        removeById(entity.getId());
    }

    @Override
    public void removeById(long id) {

        Client clientDb = entityManager.find(Client.class, id);

        if (clientDb != null) {
            clientDb.setState('I');
            for (Location location : clientDb.getLocation()) {
                locationDao.removeById(location.getId());
            }
        }

    }

}

单元测试:

@Test
public void testRemove() {
    //prepare
    //execute
    clientDao.removeById(1);
    //assert
    assertThat(clientDao.findAll()).hasSize(0);
}

测试结果:

java.lang.AssertionError: expected size:<0> but was:<1> for <[com.redacted.dto.ClientDTO@e542e8ee]>
    at org.fest.assertions.Fail.failure(Fail.java:228)
    at org.fest.assertions.Assert.failure(Assert.java:149)
    at org.fest.assertions.GroupAssert.hasSize(GroupAssert.java:89)
    at com.redatcted.dao.ClientDaoTest.testRemove(ClientDaoTest.java:139)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:233)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:87)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:176)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

2 个答案:

答案 0 :(得分:0)

好像你错过了

 entityManager.persist(clientDb);
您在addOrUpdate方法中使用的

需要LocationDao实现才能对removeById发表评论。但是,您只需从父记录ClientDb中清除位置列表并调用删除孤儿

答案 1 :(得分:0)

韦尔普!找到了罪魁祸首。

每个实体都扩展了一个名为ModelBase的映射超类,并且在那个ModelBase中有一些代码,这让我很困惑。

代码:

@PreUpdate
private void preUpdate() {
    edited = LocalDateTime.now();

    if (state != 'A' || state != 'I') {
        state = 'A';
    }
}
你能发现它吗? 是的,||应该是&&。每当我将状态设置为“I”时,在更新表preUpdate之前会调用它,看到第一个子句(state != 'A')为false并立即将状态设置回“A”。

关于这一切的最好的事情是什么?我写了那段代码。

非常感谢所有试图提供帮助的人。

P.S。:在任何人问我为什么使用char作为状态而不是布尔值之前,答案是将来会有多个状态。