【问题标题】:Spring framework JPA2 @OneToMany relationship on GAEGAME中的Spring框架JPA 2 @OneToMany关系
【发布时间】:2014-08-13 17:48:28
【问题描述】:

我正在使用 Spring 框架 4.0.5 和 Spring Data jpa 1.3.5 开发 GAE。 我正在尝试检索 OneToMany 关系中的对象列表,但收到以下错误:

您刚刚尝试访问字段“organizationMemberships”,但在您分离对象时该字段并未分离。要么不要访问该字段,要么在分离对象时将其分离。

用户实体是:

@Entity
@Table(name="users")
@NamedQuery(name="User.findAll", query="SELECT u FROM User u")
public class User implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO )
    private Long id;

    private String email;

    private String password;

    private String salt;

    private String slug;

    private int status;

    private String username;

    //bi-directional one-to-one association to UserContact
    @OneToOne(mappedBy="user")
    private UserContact userContact;

    //bi-directional one-to-one association to UserDetail
    @OneToOne(mappedBy="user", cascade = CascadeType.ALL)
    private UserDetail userDetail;

    //bi-directional many-to-one association to UsersApisession
    @OneToMany(mappedBy="user")
    private List<UsersApisession> usersApisessions;

    @OneToMany(mappedBy="user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<OrganizationMember> organizationMemberships;

    ...

}

虽然组织成员是:

@Entity
@Table(name="organization_members")
@NamedQuery(name="OrganizationMember.findAll", query="SELECT o FROM OrganizationMember o")
public class OrganizationMember implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO )
    private Long id;

    private String email;

    private int status;

    //bi-directional many-to-one association to Organization
    @ManyToOne
    private Organization organization;

    //bi-directional many-to-one association to User @JoinColumn(name="member_id")
    @ManyToOne(fetch = FetchType.LAZY)
    private User user;

    //bi-directional many-to-one association to OrganizationPosition
    @ManyToOne
    @JoinColumn(name="position_id")
    private OrganizationPosition organizationPosition;

    ...

}

我的 userRepository 是一个根据 Spring JPA 的接口:

@Transactional
public interface UserRepository extends JpaRepository<User, Long>{

    User findByEmail(String email);

    User findBySlug(String slug);
}

我的控制器代码如下:

@Controller
public class ProtectedSiteController {

    ...

    @Autowired
    private UserRepository userRepo;

    @RequestMapping(method = RequestMethod.GET, value="/afterLogin")
    public String afterLogin(HttpServletRequest request, HttpServletResponse response){

        Authentication auth = SecurityContextHolder.getContext().getAuthentication();

        User user = userRepo.findByEmail(auth.getName());

        List<OrganizationMember> memberList = user.getOrganizationMemberships();

        ...
    }
}

这是我的交易配置:

@Configuration
@EnableJpaRepositories("com.example.repository")
@EnableTransactionManagement
public class JpaApplicationConfig {

    private static final Logger logger = Logger
            .getLogger(JpaApplicationConfig.class.getName());

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(){

        Map<String, String> map = new HashMap<String, String>();
        map.put("datanucleus.NontransactionalRead","true");
        map.put("datanucleus.NontransactionalWrite","false");
        map.put("datanucleus.storeManagerType","rdbms");
        map.put("datanucleus.autoCreateSchema" ,"false");
        map.put("datanucleus.validateTables" ,"false");
        map.put("datanucleus.validateConstraints" ,"false");
        map.put("datanucleus.jpa.addClassTransformer" ,"true");
        map.put("datanucleus.singletonEMFForName", "true");

        LocalContainerEntityManagerFactoryBean lce= new LocalContainerEntityManagerFactoryBean();
        lce.setPersistenceProviderClass(org.datanucleus.api.jpa.PersistenceProviderImpl.class);

        DriverManagerDataSource dmds = new DriverManagerDataSource();
        dmds.setDriverClassName("com.mysql.jdbc.Driver");
        dmds.setUrl("jdbc:mysql://localhost:3306/example");
        dmds.setUsername("example");
        dmds.setPassword("example");

        lce.setDataSource(dmds);
        lce.setPackagesToScan("com.example.models");
        lce.setJpaPropertyMap(map);
        lce.setLoadTimeWeaver(new org.springframework.instrument.classloading.SimpleLoadTimeWeaver());
        return lce; 
    }

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf){
        logger.info("Loading Transaction Manager...");
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(emf);
        return txManager;
    }

    @Bean
    public PersistenceAnnotationBeanPostProcessor postProcessor(){
        return new PersistenceAnnotationBeanPostProcessor();
    }

}

我遵循了 GAE 教程或 Spring 教程。我的错误是什么? 谢谢你。

【问题讨论】:

    标签: spring google-app-engine jpa jpa-2.0


    【解决方案1】:

    快速的技巧是

    装上方法 afterLogin(..) @Transactional..

    问题是当用户返回时,事务被关闭,因此无法检索组织成员资格(分离)。

    另一种解决方案是在 EAGER 中更改 fetch 类型,@OneToMany 默认为 LAZY。

    @Service
    public class ServiceClass {
    
        ...
    
        @Autowired
        private UserRepository userRepo;
    
        @Transactional
        public List<OrganizationMember> method(String name){
    
            User user = userRepo.findByEmail(name);
    
            return user.getOrganizationMemberships();
    
        }
    }
    
    @Controller
    public class ProtectedSiteController {
    
        ...
    
        @Autowired
        private ServiceClass serviceClass;
    
        @RequestMapping(method = RequestMethod.GET, value="/afterLogin")
        public String afterLogin(HttpServletRequest request, HttpServletResponse response){
    
            Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    
            List<OrganizationMember> memberList = serviceClass.method(auth.getName());
    
            ...
        }
    }
    

    我希望我已经为您提供了有关您问题的所有答案。

    【讨论】:

    • 第二种解决方案有效。但我想尝试我喜欢在其他场景中使用的第一个解决方案。我在方法上添加了事务,但在加载时出现此错误:无法生成类的 CGLIB 子类 ... java.lang.LinkageError:加载程序(com/google/appengine/tools/development/IsolatedAppClassLoader 的实例):尝试对名称进行重复的类定义。我在课堂上使用了@Scope,但是使用 Scope(value="session", proxyMode = ScopedProxyMode.INTERFACES) 我有一个 404,使用 Scope(value="session", proxyMode = ScopedProxyMode.NO) 我有一个运行时例外。
    • 是的..我认为第一个解决方案比第二个更干净...我在单例 bean 上使用@Transactiona ...您应该配置 transactionManger 来处理会话 bean
    • 尝试删除 proxyMode = ScopedProxyMode.NO... trasactionManager 应该使用代理开始并提交事务
    • 我在原帖中添加了事务管理器配置。你能看看吗?如果我删除 ScopedProxyMode,则会出现 CGLIB 错误。
    • CGLIB 错误正是这样:无法生成类 [class com.example.web.controller.ProtectedSiteController] 的 CGLIB 子类:此问题的常见原因包括使用最终类或不可见类;
    猜你喜欢
    • 1970-01-01
    • 2021-02-10
    • 1970-01-01
    • 2019-01-12
    • 1970-01-01
    • 1970-01-01
    • 2017-01-23
    • 1970-01-01
    • 2019-10-25
    相关资源
    最近更新 更多