2014-04-25 56 views
1

有使用彈簧數據的CrudRepository以下測試設置彈簧數據detchated實體子對象上

@Test 
public void testCreateEventsThatShareALocation() { 
    createFirstPlannedEvent(); 
    createSecondPlannedEvent(); 
} 

@Transactional 
private void createSecondPlannedEvent() { 
    PlannedEvent plannedEvent = new PlannedEvent(); 
    Location location = locationRepository.findByName(LOCATION_NAME); 
    plannedEvent.setLocation(location); 
    plannedEventRepository.save(plannedEvent); 
} 

@Transactional 
public void createFirstPlannedEvent() { 
    PlannedEvent plannedEvent = new PlannedEvent(); 
    Location location = createLocation(LOCATION_NAME); 
    plannedEvent.setLocation(location); 
    plannedEventRepository.save(plannedEvent); 
} 

public Location createLocation(String name) { 
    Location location = new Location(); 
    location.setName(name); 
    location.setSomeOtherStuff....(); // Does NOT call the repository save method of Location (there is no repository for Location) 
    return location; 
} 

當我運行這個測試我得到,嘗試存儲第二PlannedEvent時:

Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: com.eventage.entities.Location 

當我通過代碼進行調試時,我注意到PlannedEvent的第一次創建沒有問題,但在第二次創建時失敗。

目前的SimpleJpaRepository

entityInformation.isNew(entity) 

保存方法內將返回true,並試圖挽救第二個實體時拋出上述異常。

它將實體視爲新實體的事實是正常的,因爲它的id值爲空。

我不明白如何將位置分離出來,因爲我在將它分配到PlannedEvent之前將其提取出來?

可能是因爲locationRepository和plannedEventRepository使用了entityManager的不同實例嗎?

當我在save方法中斷開並調用.merge而不是.persist時,它很好地存儲了第二個PlannedEvent,爲什麼?

回答

1

儘管您的方法使用Transactional註釋,但事實並非如此。

Spring事務是基於代理的。這意味着Spring將攔截從一個Spring bean到另一個Spring bean的調用,這要歸功於代理,並且啓動/提交事務是這個其他bean的方法是事務性的。

Spring無法攔截從一個對象到同一個對象的方法調用。因此,每次調用存儲庫時,實際上都有一個事務。這就是您的位置被分離的原因。