我有一个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)
答案 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作为状态而不是布尔值之前,答案是将来会有多个状态。