2014-05-01 57 views
0

我有一個類,有幾個懶惰的初始化收藏,OneToManyManyToManyManyToMany關係是單向的,因此Expert類沒有Project集合。ManyToMany收藏不斷被刪除

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "project") 
private List<Logging> loggings = new ArrayList<Logging>(); 

@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) 
@JoinTable(name = "project_expert", joinColumns = { @JoinColumn(name = "project") }, inverseJoinColumns = { @JoinColumn(name = "expert") }) 
private List<Expert> experts = new ArrayList<Expert>(); 

public void add(Logging logging) { 
    logging.setProject(this); 
    this.loggings.add(logging); 
} 

public void add(Expert expert) { 
    this.experts.add(expert); 
} 

對象添加到OneToMany集合,我這樣做:

Project project = projectService.save(projectForm.getProject()); 
Logging logging = new Logging(); 
project.add(logging); 
logging = loggingService.save(logging); 

這工作得很好。然而,當我嘗試的元素添加到ManyToMany,那麼這個集合似乎在保存父對象被刪除了,所以我不能添加多個子對象:

@RequestMapping(value="/newexpert", method=RequestMethod.POST) 
public String newExpert(@ModelAttribute("projectForm") ProjectForm projectForm, BindingResult result, ModelMap model) { 

    Project project = projectService.save(projectForm.getProject()); 
    Expert expert = projectForm.getExpert(); 
    if (expert != null) { 
     project.add(expert); 
    } 
    project = projectService.save(project); 

    return "redirect:/project/" + project.getId(); 
} 

這是什麼服務方法看起來像(projectRepository擴展PagingAndSortingRepository):

@Override 
@Transactional 
public Project save(Project project) { 
    return projectRepository.save(project); 
} 

在日誌中,我發現這一點:

2014-05-01 17:01:49 DEBUG AbstractCollectionPersister:1174 - Deleting collection: [test.model.Project.experts#1] 
2014-05-01 17:01:49 DEBUG SQL:109 - delete from project_expert where project=? 
2014-05-01 17:01:49 DEBUG AbstractCollectionPersister:1232 - Done deleting collection 

編輯1:這是在save(projectForm.getProject())會發生什麼:

2014-05-01 18:30:04 DEBUG Loader:2136 - Loading entity: [test.model.Project#1] 
2014-05-01 18:30:04 DEBUG SQL:109 - select project0_.id as id1_4_1_, ... from Project project0_ left outer join project_expert experts1_ on project0_.id=experts1_.project left outer join Expert expert2_ on experts1_.expert=expert2_.id where project0_.id=? 
2014-05-01 18:30:04 DEBUG Loader:951 - Result set row: 0 
2014-05-01 18:30:04 DEBUG Loader:1485 - Result row: EntityKey[test.model.Expert#2], EntityKey[test.model.Project#1] 
2014-05-01 18:30:04 DEBUG Loader:1305 - Found row of collection: [test.model.Project.experts#1] 
2014-05-01 18:30:04 DEBUG TwoPhaseLoad:160 - Resolving associations for [test.model.Project#1] 
2014-05-01 18:30:04 DEBUG TwoPhaseLoad:286 - Done materializing entity [test.model.Project#1] 
2014-05-01 18:30:04 DEBUG CollectionLoadContext:232 - 1 collections were found in result set for role: test.model.Project.experts 
2014-05-01 18:30:04 DEBUG CollectionLoadContext:280 - Collection fully initialized: [test.model.Project.experts#1] 
2014-05-01 18:30:04 DEBUG CollectionLoadContext:240 - 1 collections initialized for role: test.model.Project.experts 
2014-05-01 18:30:04 DEBUG Loader:2160 - Done entity load 
2014-05-01 18:30:04 DEBUG AbstractTransactionImpl:175 - committing 
2014-05-01 18:30:04 DEBUG AbstractFlushingEventListener:149 - Processing flush-time cascades 
2014-05-01 18:30:04 DEBUG AbstractFlushingEventListener:189 - Dirty checking collections 
2014-05-01 18:30:04 DEBUG CollectionEntry:202 - Collection dirty: [test.model.Project.loggings#1] 
2014-05-01 18:30:04 DEBUG CollectionEntry:202 - Collection dirty: [test.model.Project.parties#1] 
2014-05-01 18:30:04 DEBUG CollectionEntry:202 - Collection dirty: [test.model.Project.experts#1] 
2014-05-01 18:30:04 DEBUG Collections:194 - Collection found: [test.model.Project.experts#1], was: [test.model.Project.experts#1] (initialized) 
2014-05-01 18:30:04 DEBUG Collections:201 - Collection found: [test.model.Project.loggings#1], was: [test.model.Project.loggings#1] (uninitialized) 
2014-05-01 18:30:04 DEBUG Collections:201 - Collection found: [test.model.Project.parties#1], was: [test.model.Project.parties#1] (uninitialized) 
2014-05-01 18:30:04 DEBUG AbstractFlushingEventListener:123 - Flushed: 0 insertions, 0 updates, 0 deletions to 3 objects 
2014-05-01 18:30:04 DEBUG AbstractFlushingEventListener:130 - Flushed: 0 (re)creations, 3 updates, 0 removals to 3 collections 
2014-05-01 18:30:04 DEBUG EntityPrinter:114 - Listing entities: 
2014-05-01 18:30:04 DEBUG EntityPrinter:121 - test.model.Expert{id=2, ...} 
2014-05-01 18:30:04 DEBUG EntityPrinter:121 - test.model.Project{..., id=1, ...} 
2014-05-01 18:30:04 DEBUG EntityPrinter:121 - test.model.Expert{id=1, ...} 
2014-05-01 18:30:04 DEBUG SQL:109 - select count(id) from Logging where project_id =? 
2014-05-01 18:30:04 DEBUG SQL:109 - select count(id) from Party where project_id =? 
2014-05-01 18:30:04 DEBUG AbstractCollectionPersister:1174 - Deleting collection: [test.model.Project.experts#1] 
2014-05-01 18:30:04 DEBUG SQL:109 - delete from project_expert where project=? 
2014-05-01 18:30:04 DEBUG AbstractCollectionPersister:1232 - Done deleting collection 
2014-05-01 18:30:04 DEBUG JdbcTransaction:113 - committed JDBC Connection 
2014-05-01 18:30:04 DEBUG JdbcTransaction:126 - re-enabling autocommit 
... 
2014-05-01 18:30:04 DEBUG AbstractLoadPlanBasedCollectionInitializer:88 - Loading collection: [test.model.Project.loggings#1] 
2014-05-01 18:30:04 DEBUG SQL:109 - select loggings0_.project_id as project_5_4_0_, loggings0_.id as id1_2_0_, ... from Logging loggings0_ where loggings0_.project_id=? 
2014-05-01 18:30:04 DEBUG ResultSetProcessorImpl:168 - Preparing collection intializer : [test.model.Project.loggings#1] 
2014-05-01 18:30:04 DEBUG ResultSetProcessorImpl:127 - Starting ResultSet row #0 
2014-05-01 18:30:04 DEBUG CollectionReferenceInitializerImpl:77 - Found row of collection: [test.model.Project.loggings#1] 
2014-05-01 18:30:04 DEBUG TwoPhaseLoad:160 - Resolving associations for [test.model.Logging#1] 
2014-05-01 18:30:04 DEBUG TwoPhaseLoad:286 - Done materializing entity [test.model.Logging#1] 
2014-05-01 18:30:04 DEBUG CollectionLoadContext:232 - 1 collections were found in result set for role: test.model.Project.loggings 
2014-05-01 18:30:04 DEBUG CollectionLoadContext:280 - Collection fully initialized: [test.model.Project.loggings#1] 
2014-05-01 18:30:04 DEBUG CollectionLoadContext:240 - 1 collections initialized for role: test.model.Project.loggings 
2014-05-01 18:30:04 DEBUG AbstractLoadPlanBasedCollectionInitializer:118 - Done loading collection 

編輯2:顯然,ManyToMany集合中的父對象projectForm.getProject()初始化而空。怎麼可能?我期望它是單元化的,或者如果它由於某種原因被初始化,不是空的?

+0

您能否顯示'Project'類的'add'方法?這是一種多態的方法,可以採用Logging或Expert這個參數,對吧?和'projectService.save()'。 –

+0

我已經編輯了我的帖子。 – user3170702

+0

將FetchType.LAZY更改爲FetchType.EAGER,並查看它是否至少在getProject()中提供了值。如果將該對象聲明爲lazily加載,Hibernate將初始化一個空集合,直到嘗試使用它時纔會填充它。 – JamesENL

回答

0

我想我可能有罪魁禍首。

你初始化多對多集合作爲

private List<Expert> experts = new ArrayList<Expert>(); 

,然後你add()方法訪問集合爲this.experts.add(..)。然而ManyToMany協會是LAZY。那麼JPA提供程序如何知道您不打算用新的集合重寫集合呢?

嘗試改變add()與吸氣的集合,如

public void add(Expert expert) { 
    this.getExperts().add(expert); 
} 
+0

不幸的是,這並沒有奏效。我添加了更多日誌,因爲當我保存從窗體返回的對象時,可以看到集合被刪除。該對象沒有任何初始化的集合,但這不會導致'OneToMany'集合被覆蓋。我認爲它也適用於'ManyToMany'集合。 – user3170702

+1

好的,我稍後再看看。順便說一句,爲什麼你需要在你的ManyToMany關係中使用'CascadeType.ALL'? –

+0

正確,我不需要'CascadeType.ALL',會改變它。 – user3170702

1

在服務這​​樣的創建方法:

@Transactional 
public Project addExperts(Project project, List<Expert> experts){ 
    List<Expert> projectExperts = project.getExperts(); 
    for(Expert expert: experts){ 
     projectExperts.add(expert); 
    } 

    project.setExperts(projectExperts); 
    return project; 
} 

這將封裝在一個事務中Project.experts的取這樣可以正確地取得並初始化延遲加載的集合。通過添加您在控制器中確定的列表,然後可以正確保存項目並使級聯創建新的專家對象。我很確定這應該解決您的問題。

如果您沒有看到INSERT聲明創建您的Expert對象,那多數民衆贊成你的問題。如果它們不存在於數據庫中,Hibernate無法將對Expert對象的引用插入到JoinTable中,因此它會刪除您的集合對象。

+0

事實上,沒有'Expert'對象被創建,數據庫中有一個或多或少的固定集合。你的建議是有效的,但是隻有當我明確地從數據庫中獲取項目,獲得其'expert'集合,添加'expert',並將集合附加到來自控制器的新'project'對象時。然後在控制器中調用'save'服務,一切正常。這是正常的嗎?謝謝! – user3170702

+0

我也注意到當我只做一次保存時,集合被刪除,所以必須將'save'服務更改爲首先從數據庫中獲取集合。我能做些什麼呢? – user3170702

+0

因爲你的集合是懶惰加載的,所以Hibernate不會將它們從數據庫中拉出來,除非你特別問它。您可以將您的集合設置爲「FetchType.EAGER」,以便在將對象從數據庫中取出時集合被初始化。 – JamesENL