1

在我的 java spring webapp 中,我有关系:一个帐户可以有多个组,一个组只能有一个帐户。

集团实体:

@Entity
@Table(name = "group")
@Inheritance(strategy = InheritanceType.JOINED)
public class Group {

@Id
@GeneratedValue(generator = "group_id", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(name = "group_id", sequenceName = "group_group_id_seq", allocationSize = 1)
@Column(name = "group_id")
private Long id;

@Basic
@NotBlank
@Column(name = "name")
private String name;

@ManyToOne(targetEntity = Account.class, fetch = FetchType.LAZY)
@JoinColumn(name = "account_id")
private Account account;

@Basic
@NotBlank
@Column(name = "all")
private boolean all;

@ManyToMany(targetEntity = Word.class, fetch = FetchType.LAZY)
@JoinTable(name = "group_word", joinColumns = {@JoinColumn(name="group_id")}, inverseJoinColumns = {@JoinColumn(name="word_id")})
private List<Word> words;

getters/setters...

账户实体:

@Entity
@JsonIgnoreProperties(ignoreUnknown = true)
@Table(name = "account")
@Inheritance(strategy = InheritanceType.JOINED)
public class Account  extends User implements UserDetails {

@Id
@GeneratedValue(generator = "account_id", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(name = "account_id", sequenceName = "account_account_id_seq", allocationSize = 1)
@Column(name = "account_id")
private Long accountId;

@Column(name = "username")
private String username;

@Column(name = "password")
private String password;

@Transient
private String repeatedPassword;

@DateTimeFormat(iso = ISO.DATE_TIME)
@Column(name = "registration_date")
Date registrationDate = Calendar.getInstance().getTime();

@Column(name = "email")
private String email;

@ManyToMany(targetEntity = Role.class, fetch = FetchType.LAZY)
@JoinTable(name = "account_role", joinColumns = {@JoinColumn(name="account_id")}, inverseJoinColumns = {@JoinColumn(name="role_id")})
private List<Role> roles;

public List<Role> getRoles() {
    return roles;
}

public void setRoles(List<Role> roles) {
    this.roles = roles;
}

@OneToMany(mappedBy="account", fetch = FetchType.LAZY)
private List<Group> groups;

public List<Group> getGroups() {
    return groups;
}

public void setGroups(List<Group> groups) {
    this.groups = groups;

getters/setters...

当我调用此服务方法时:

public List<Group> listUserGroups(String username) {
    try {
        Account foundAccount = accountDao.findUserByUsername(username);
        List<Group> userGroups = foundAccount.getGroups();
        userGroups.size();
        return userGroups;
    } catch (UserNotFoundException unf) {
        logger.error("User not found: " + username, unf.getMessage());
        return Collections.emptyList();
    }
}

我有一个错误在线:

userGroups.size();

错误:

00:27:27,528 DEBUG [org.hibernate.engine.StatefulPersistenceContext] - initializing non-lazy collections
00:27:27,528 DEBUG [org.hibernate.loader.Loader] - loading collection: [pl.net.grodek.snd.model.Account.groups#116]
00:27:27,528 DEBUG [org.hibernate.jdbc.AbstractBatcher] - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
00:27:27,528 DEBUG [org.hibernate.SQL] - select groups0_.account_account_id as account4_20_1_, groups0_.group_id as group1_1_, groups0_.group_id as group1_19_0_, groups0_.account_account_id as account4_19_0_, groups0_.all as all19_0_, groups0_.name as name19_0_ from group groups0_ where groups0_.account_account_id=?
00:27:27,544 DEBUG [org.hibernate.jdbc.AbstractBatcher] - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
00:27:27,544 DEBUG [org.hibernate.util.JDBCExceptionReporter] - could not initialize a collection: [pl.net.grodek.snd.model.Account.groups#116] [select groups0_.account_account_id as account4_20_1_, groups0_.group_id as group1_1_, groups0_.group_id as group1_19_0_, groups0_.account_account_id as account4_19_0_, groups0_.all as all19_0_, groups0_.name as name19_0_ from group groups0_ where groups0_.account_account_id=?]
org.postgresql.util.PSQLException: ERROR: syntax error near "group"
Position: 227
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2103)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1836)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:257)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:512)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:388)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:273)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeQuery(NewProxyPreparedStatement.java:76)
at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208)
at org.hibernate.loader.Loader.getResultSet(Loader.java:1953)
at org.hibernate.loader.Loader.doQuery(Loader.java:802)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274)
at org.hibernate.loader.Loader.loadCollection(Loader.java:2166)
at org.hibernate.loader.collection.CollectionLoader.initialize(CollectionLoader.java:62)
at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:627)
at org.hibernate.event.def.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:83)
at org.hibernate.impl.SessionImpl.initializeCollection(SessionImpl.java:1863)
at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:369)
at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:111)
at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:134)
at org.hibernate.collection.PersistentBag.size(PersistentBag.java:248)
at pl.net.grodek.snd.service.GroupServiceImpl.listUserGroups(GroupServiceImpl.java:47)
at pl.net.grodek.snd.service.GroupServiceImpl.listUserGroups(GroupServiceImpl.java:1)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at 

我认为问题出在 jpa 生成的查询中:

select groups0_.account_account_id as account4_20_1_, groups0_.group_id as group1_1_, groups0_.group_id as group1_19_0_, groups0_.account_account_id as account4_19_0_, groups0_.all as all19_0_, groups0_.name as name19_0_ from group groups0_ where groups0_.account_account_id=?

其中 account_id 和 group_id 加倍。但我的问题是为什么会这样。请为我澄清这个问题,因为我没有想法:(

编辑:

哦,我忘了数据库表:

CREATE TABLE "group"
(
    group_id bigserial NOT NULL,
    name character varying(150)[] NOT NULL,
    "all" boolean NOT NULL DEFAULT false,
    account_id bigint NOT NULL,
    CONSTRAINT group_id_pk PRIMARY KEY (group_id ),
    CONSTRAINT account_id_fk FOREIGN KEY (account_id)
    REFERENCES account (account_id) MATCH SIMPLE
    ON UPDATE NO ACTION ON DELETE NO ACTION
)

CREATE TABLE account
(
    account_id bigserial NOT NULL,
    username character varying(32),
    password character varying(64),
    email character varying(100),
    registration_date timestamp with time zone NOT NULL,
    word_for_today bigint,
    groups_on_page integer NOT NULL,
    CONSTRAINT account_pk PRIMARY KEY (account_id ),
    CONSTRAINT word_fk FOREIGN KEY (word_for_today)
  REFERENCES word (word_id) MATCH SIMPLE
  ON UPDATE NO ACTION ON DELETE NO ACTION,
    CONSTRAINT unique_mail UNIQUE (email ),
    CONSTRAINT unique_username UNIQUE (username )
)
4

2 回答 2

0

In my experience the problem is related with the scope of the persistence context. You are using a DAO to retrive the entities so maybe you pretend to access properties of a deattached entity.
Talking light, maybe, inside the scope of the accountDao.findUserByUsername() function you intialize/instance the persistence context when you retrive a entity through the entity manager but after the object return, the scope of this function end and the instance of the persistence context (entityManager) with it. In other word, in a Java SE app enviroment, you are not referencing the entityManager in a static way to stay it alive at all of your app running scope.

Apart of this, Hibernate works with proxies. It means that, following your example, you retrive the object Account with all basic attributes loaded but on the contrary the lazy relationships (groups, roles, etc.). When invoke getGroups() doesn't force the proxy to query for the list of groups, but when you invoke size the proxy must query for them. To better undestanding of this and Hibernate behavior in general I recommend you the chapter 13 Understanding proxies of the book Hibernate in Action - Java Persistence with Hibernate (isbn 1-932394-88-5)

Regards

于 2012-10-27T00:17:24.567 回答
0

I changed group table name to groups and it works. but please can anyone tell me why is that. With earlier relationships i did not have such mysterious problems. I am loosing ma sanity. :(

Maybe someone sees a problem in my code? Are my account->group relationships well set?

EDIT: As @AdrianShum said group is a SQL keyword so that my mapping worked when I changed to another name

于 2012-10-28T23:25:40.363 回答