GROM create needless table with many-to-many mappi

2019-06-13 20:48发布

问题:

I have problem about many-to-many mapping.

[Case]

  • Account owns Community(owner)
  • Community has many Account(members)

GORM create four tables:

  • ACCOUNT
  • COMMUNITY
  • COMMUNITY_MEMBERS
  • COMMUNITY_OWNER

GORM creates a table "COMMUNITY_OWNER (ACCOUNT_ID, OWNER_ID)". Why GORM creating this?

This table is not used.(Please look at Hibernate log) I want GORM to not create COMMUNITY_OWNER. My mapping is wrong?

Related Question: cascade delete with many-to-many mapping in Grails

[Domain Class]

class Account {

  String name

  static hasMany = [communities: Community]
  static belongsTo = [Community]
}

class Community {

  String name
  Account owner

  static hasMany = [members: Account]

  static mapping = {
    owner cascade: 'none'
  }
}

[TestCode]

def admin = new Account(name: 'admin').save(flush:true)
def user = new Account(name: 'user').save(flush:true)

def c = new Community(name: 'TestCommunity')

c.owner = admin

c.addToMembers(admin)
c.addToMembers(user)            
c.save(flush:true)

c.removeFromMembers(user)
c.save(flush:true)

c.delete(flush:true)

[Hibernate Log]

INFO  hbm2ddl.SchemaExport  - Running hbm2ddl schema export
DEBUG hbm2ddl.SchemaExport  - import file not found: /import.sql
INFO  hbm2ddl.SchemaExport  - exporting generated schema to database
DEBUG hbm2ddl.SchemaExport  - drop table account if exists
DEBUG hbm2ddl.SchemaExport  - drop table community if exists
DEBUG hbm2ddl.SchemaExport  - drop table community_members if exists
DEBUG hbm2ddl.SchemaExport  - drop table community_owner if exists
DEBUG hbm2ddl.SchemaExport  - create table account (id bigint generated by default as identity, version bigint not null, name varchar(255) not null, primary key (id))
DEBUG hbm2ddl.SchemaExport  - create table community (id bigint generated by default as identity, version bigint not null, name varchar(255) not null, owner_id bigint not null, primary key (id))
DEBUG hbm2ddl.SchemaExport  - create table community_members (community_id bigint not null, account_id bigint not null, primary key (community_id, account_id))

<<Why create?>> 
DEBUG hbm2ddl.SchemaExport  - create table community_owner (account_id bigint not null, owner_id bigint not null)

DEBUG hbm2ddl.SchemaExport  - alter table community add constraint FKA7C52FE92BBE477B foreign key (owner_id) references account
DEBUG hbm2ddl.SchemaExport  - alter table community_members add constraint FK5A8DA6C3C4A6EE81 foreign key (community_id) references community
DEBUG hbm2ddl.SchemaExport  - alter table community_members add constraint FK5A8DA6C398BAC5C1 foreign key (account_id) references account
DEBUG hbm2ddl.SchemaExport  - alter table community_owner add constraint FK12E232DD98BAC5C1 foreign key (account_id) references account
DEBUG hbm2ddl.SchemaExport  - alter table community_owner add constraint FK12E232DD8BE4BF77 foreign key (owner_id) references community
INFO  hbm2ddl.SchemaExport  - schema export complete

<<community_owner not used>>
DEBUG hibernate.SQL  - insert into account (id, version, name) values (null, ?, ?)
DEBUG hibernate.SQL  - insert into account (id, version, name) values (null, ?, ?)
DEBUG hibernate.SQL  - insert into community (id, version, name, owner_id) values (null, ?, ?, ?)
DEBUG hibernate.SQL  - update account set version=?, name=? where id=? and version=?
DEBUG hibernate.SQL  - update account set version=?, name=? where id=? and version=?
DEBUG hibernate.SQL  - insert into community_members (community_id, account_id) values (?, ?)
DEBUG hibernate.SQL  - update account set version=?, name=? where id=? and version=?
DEBUG hibernate.SQL  - update community set version=?, name=?, owner_id=? where id=? and version=?
DEBUG hibernate.SQL  - delete from community_members where community_id=? and account_id=?
DEBUG hibernate.SQL  - delete from community_members where community_id=?
DEBUG hibernate.SQL  - delete from community where id=? and version=?

回答1:

Looking at your mapping, I believe your case is slightly off (as well as the mapping). Did you mean to say ...

Account has many Community (as 'communities')
Community has many Account (as 'members')

this would be a true many-to-many. Also from your mapping, I'm assuming you'd like Account to be the owning side of the many-to-many. If this the case, then you can do something like the following.

class Account {
 ..
 static hasMany = [communities: Community]
 static mappedBy = [communities: 'owner']  //<-- will not work without this mapping
} 

class Community {
 ..
 static belongsTo = [owner: Account] //<-- assumes Account is owner
 static hasMany = [members: Account]
}

NOTE: the belongsTo in Community assumes Account will be the "owner". The mappedBy is needed otherwise Grails will blow up (here's a discussion about it).

You'll end up with the Account and Community tables and a third mapping table - no fourth table.

  • the mapping table will handle the Community "has many members" relationship
  • the Account "has many communities" relationship is handled by a foreign key on the Community table back to Account.