2016-07-01 5 views
0

私はUserを取得し、そのUserConfigをマップした後、そのUserConfigでMainBrands(UserConfigurationの遅延コレクション)を取得するコントローラメソッドを持っています。これのためのSpring MVCのトランザクションのベストプラクティス

は、私はこのことを明確にしましょう:

ユーザエンティティ:

@Entity 
@Table(name = "app_user") 
public class User extends BaseEntity { 

    private UserConfig userConfig;   

    @OneToOne(mappedBy = "user", cascade = CascadeType.ALL) 
    public UserConfig getUserConfig() { 
     return userConfig; 
    } 

    //more props.. 
} 

UserConfigにエンティティ:

@Entity 
@Table(name = "user_config") 
public class UserConfig extends BaseEntity { 

    private Set<MainBrand> mainBrands; 

    @ManyToMany(fetch = FetchType.LAZY) 
    @JoinTable(...) 
    public Set<MainBrand> getMainBrands() { 
     return mainBrands; 
    } 

    //more props.. 

} 

そして、私のUserServiceの:

public interface UserService { 

    public User getById(Long id); 

} 

だから私の質問はおよそです」ベストプラクティス" トランザクションアノテーションの私は二度以上読んだことがあります。コントローラレベルで@Transactionalを置くと、悪い習慣です。しかし、この場合には、私はコントローラーで行いたい。なぜならLazyInitializationExceptionで、コントローラレベルで@Transactional注釈を入れていない場合に失敗します

@RequestMapping(method = RequestMethod.GET, value = "/") 
public ModelAndView getMainPage(Long userId) { 

    ModelAndView = new ModelAndView("/home"); 

    //do stuff 

    User user = userService.getById(userId); 

    //some stuff with user 
    modelAndView.addObject("username", user.getUsername()); 
    //... 

    List<String> brandsNames = new ArrayList<>(); 

    for(MainBrand mainBrand : user.getUserConfig().getMainBrands()){ 
     brandsNames.add(mainBrand.getName()); 
    } 
} 

。ユーザーとの

1)は今(それが作成されていない「UserConfigService」に電話をかける)userConfigService.getUserConfigByUserId(USERID)のように:

だから、それは私が出てthinkedてきた選択肢をということです私はUserクラスでバインディングをすでに持っていれば、なぜ私は再びそれを呼び出すのだろうと思いますか?そして、私はこのメソッドのためだけに新しいサービスを作成しています。

2) @Transactionalアノテーションをコントローラーレベルに設定します。これは、私の別の問題ですが、このポストでは気にしません。 。

3)コールUserServiceのでgetUserConfig()& getUserConfig()getMainBrands()ので、コレクションが初期化:私はgetByIdを使用するときので、それは私がいない場合でも、コレクションを初期化します好きではありませんそれが必要。

この場合、どのような場合がよいでしょうか?インターネット上には、常に完璧で美しい例がありますが、プロジェクトにいくつかのビジネスロジックを与え始めると、クリーンなコードを作るのが難しくなります。

ありがとう、ごめんなさい、私の英語です。

答えて

0

LazyInitializationExceptionがトランザクションに関連していない、それはオブジェクト間の関係に関連して、あなたのオブジェクトは怠惰な関係を持っている場合あなたが戻る前に、あなたはあなたのuserService.getById(USERID)クエリメソッドであなたのMainBrandsオブジェクトをフェッチする必要がありますあなたのユーザー。

トランザクションアノテーションはサービスクラスに属している必要があります。必要な数のサービスクラスを作成できます。

+0

しかし、別のコントローラメソッドで同じサービスメソッドを使用しても、MainBrandがフェッチされているかどうかは気にしません。私は何のためにフェッチ結合クエリをやっているだろう。それが1つの場合、問題はありません。しかし、50人のユーザーをフェッチするのはどうですか?私は私のために望んでいない質問を50回取り出すだろうか? –

+0

私はgetUserメソッドをgetUserById(long userId、boolean fetchCollections)に変更しようとしていますが、この場合、コレクションは入れ子のUserConfigオブジェクトにあります...混乱しています –

+0

これはちょうどjpaにdinamicallyを追加する方法ですCriteriaQuery。私はあなたにこのようなものをフェッチするメソッドを提案する必要があります** public void addFetches(root root、FetchElement fetch){root.fetch(fetch.getName()、fetch.getType());} ** ** FetchList.add(new FetchElement(User_mainbrands.getName)); FetchList(FetchListener); FetchListener(FetchListener); FetchListener(FetchListener); FetchElement ()、JoinType.INNER)); **これはjpaでのみ有効です。 – duardito

関連する問題