views:

108

answers:

2

Hi,

I'm new to both hibernate and java, I'm trying to define a simple user->groups->permissions model in playframework, I want the on delete cascade rule enforced at database level and I don't want the orm care about cascade (something similar to python-sqlalchemy passive deletes), here are my models:

User model:

@Entity
@Table(name="auth_user")

public class User extends Model {

    @Column(name="username",nullable=false,length=40)
    @org.hibernate.annotations.Index(name = "idx_username")
    public String username;
    @Column(nullable=false,length=255)
    public String password;
    @Column(nullable=true,length=150)
    public String email;
    @Column(nullable=true,length=150)
    public String fullname;
    @Column(nullable=true)
    public boolean isAdmin;

    @OneToMany(mappedBy="group")
    public List<UserGroup> user_groups;
}

Group model:

@Entity
@Table(name="auth_group")

public class Group extends Model {

    @Column(nullable=false,length=40)
    public String name;

    @OneToMany(mappedBy="group")
    public List<GroupPermission> group_permissions;

    @OneToMany(mappedBy="user")
    public List<UserGroup> user_groups;

Permission model:

@Entity
@Table(name="auth_permission")

public class Permission extends Model {

    @Column(nullable=false,length=40)
    public String name;
    @Column(nullable=false)
    public Integer code;

    @OneToMany(mappedBy="permission")
    public List<GroupPermission> permission_groups;

GroupPermission model:

@Entity
@Table(name="group_permissions")

public class GroupPermission extends Model {

    @ManyToOne
    @org.hibernate.annotations.OnDelete(action=org.hibernate.annotations.OnDeleteAction.CASCADE)
    public Group group;

    @ManyToOne
    @org.hibernate.annotations.OnDelete(action=org.hibernate.annotations.OnDeleteAction.CASCADE)
    public  Permission permission;

UserGroup model:

@Entity
@Table(name="user_groups")
public class UserGroup extends Model {

    @ManyToOne
    @org.hibernate.annotations.OnDelete(action=org.hibernate.annotations.OnDeleteAction.CASCADE)
    public User user;

    @ManyToOne
    @org.hibernate.annotations.OnDelete(action=org.hibernate.annotations.OnDeleteAction.CASCADE)
    public Group group;

this generate the following sql in postgres:

CREATE TABLE auth_user
(
id bigint NOT NULL,
email character varying(150),
fullname character varying(150),
isadmin boolean,
"password" character varying(255) NOT NULL,
username character varying(40) NOT NULL,
CONSTRAINT auth_user_pkey PRIMARY KEY (id)
)
WITH (
    OIDS=FALSE
);

ALTER TABLE auth_user OWNER TO postgres;
CREATE TABLE auth_group
(
id bigint NOT NULL,
"name" character varying(40) NOT NULL,
CONSTRAINT auth_group_pkey PRIMARY KEY (id)
)
WITH (
    OIDS=FALSE
);

ALTER TABLE auth_group OWNER TO postgres;

CREATE TABLE auth_permission
(id bigint NOT NULL,
 code integer NOT NULL,
 "name" character varying(40) NOT NULL,
 CONSTRAINT auth_permission_pkey PRIMARY KEY (id)
)
WITH (
    OIDS=FALSE
 );

ALTER TABLE auth_permission OWNER TO postgres;

CREATE TABLE group_permissions
(id bigint NOT NULL,
group_id bigint,
permission_id bigint,
CONSTRAINT group_permissions_pkey PRIMARY KEY (id),
CONSTRAINT fk8f9f82c43494357e FOREIGN KEY (permission_id)
    REFERENCES auth_permission (id) MATCH SIMPLE
    ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT fk8f9f82c4c8b3dcb6 FOREIGN KEY (group_id)
    REFERENCES auth_group (id) MATCH SIMPLE
    ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (
  OIDS=FALSE
);

ALTER TABLE group_permissions OWNER TO postgres;

CREATE TABLE user_groups
(id bigint NOT NULL,
 group_id bigint,
 user_id bigint,
 CONSTRAINT user_groups_pkey PRIMARY KEY (id),
 CONSTRAINT fke27720c847140efe FOREIGN KEY (user_id)
    REFERENCES auth_user (id) MATCH SIMPLE
    ON UPDATE NO ACTION ON DELETE CASCADE,
 CONSTRAINT fke27720c86e0797ca FOREIGN KEY (group_id)
    REFERENCES auth_user (id) MATCH SIMPLE
    ON UPDATE NO ACTION ON DELETE NO ACTION,
 CONSTRAINT fke27720c8a1c053ea FOREIGN KEY (user_id)
    REFERENCES auth_group (id) MATCH SIMPLE
    ON UPDATE NO ACTION ON DELETE NO ACTION,
 CONSTRAINT fke27720c8c8b3dcb6 FOREIGN KEY (group_id)
    REFERENCES auth_group (id) MATCH SIMPLE
    ON UPDATE NO ACTION ON DELETE CASCADE
 )

 WITH (
    OIDS=FALSE
 );

 ALTER TABLE user_groups OWNER TO postgres; 

as you can see the index on the username field in the tabe auth_user is not created, the constraint in the table user_groups are duplicated, I have both ON DELETE CASCADE and ON DELETE NO ACTION, I want only the cascade version, in the table group_permissions the cascade rule is not created,

what's wrong?

thanks Nicola

A: 

as you can see the index on the username field in the tabe auth_user is not created (...)

Indeed. And it clearly should get created, the annotation part looks correct. As an alternative, could you try to define the index in the Hibernate specific @Table annotation. Like this:

@Entity
@org.hibernate.annotations.Table(
    name="auth_user",
    indexes = { @Index(name="idx_username", columnNames = { "username" } ) }
    )
public class User { ... }

If this works, this would just be a workaround, the @org.hibernate.annotations.Index annotation at the attribute level should work.

the constraint in the table user_groups are duplicated, I have both ON DELETE CASCADE and ON DELETE NO ACTION, I want only the cascade version, in the table group_permissions the cascade rule is not created

Can't say, can't test, don't have much experience with the related annotations. Maybe search for existing issues in Hibernate's Jira. If you can't find anything, setup a test case and create an issue. Sorry, I don't have better suggestions.

Pascal Thivent
still no luck, there should be something really subdole in my code, thanks anyway
Nicola
@Nicola Sadly, that was my best and only suggestion.
Pascal Thivent
@Pascal, I solved the cascade problem (there was a problem in mappedBy) now I'm tryed to understand the index creation
Nicola
A: 

Not sure about that, but it reminds me of a problem I ran into once.

I had the indexes created by using "jpa.ddl=create" on the first run (and switched right back to update).

In your application.conf file:

# JPA Configuration (Hibernate)
# ~~~~~
#
# Specify the custom JPA dialect to use here (default to guess):
# jpa.dialect=org.hibernate.dialect.PostgreSQLDialect
#
# Specify the ddl generation pattern to use (default to update, set to none to disable it):
# jpa.ddl=update

# can you try this?
jpa.ddl=create

Can you try this configuration and see if the index gets created?

Just my 2 cents...

Brian Clozel