如何使用GORM创建复合主键?

时间:2011-03-31 15:50:16

标签: grails gorm indexing composite-primary-key

我有三个域类:Beer,Review和Reviewer。

我希望Review表在Beer和Reviewer之间创建多对多关系,因此我希望Review的主键是Beer和Reviewer的id字段的组合。我正在关注这个Grails文档。

http://grails.org/doc/latest/guide/5.%20Object%20Relational%20Mapping%20(GORM).html#5.5.2.5%20Composite%20Primary%20Keys

以下是我的域名类。

class Beer {
    String name
    String type
    Brewery breweryId

    static hasMany = [ reviews : Review ]

    static constraints = {
    }
}

class Reviewer {
    String screenName

    static hasMany = [ reviews : Review ]

    static constraints = {
    }
}

class Review implements Serializable {
    int score
    Beer beer
    Reviewer reviewer


    static constraints = {
    }

    static mapping = {
        id composite:['beer', 'reviewer']
    }
}

我收到了编译错误,但是stackoverflow的另一个答案是我需要添加implements Serializable。这样可以解决错误,但是当我查看数据库时,我仍然没有得到复合主键。

以下是我在查看表定义时所看到的内容。我正在使用Postgres。

       Table "public.review"
   Column    |  Type   | Modifiers 
-------------+---------+-----------
 id          | bigint  | not null
 version     | bigint  | not null
 beer_id     | bigint  | not null
 reviewer_id | bigint  | not null
 score       | integer | not null
Indexes:
    "review_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
    "fkc84ef75823f39326" FOREIGN KEY (beer_id) REFERENCES beer(id)
    "fkc84ef7587c483106" FOREIGN KEY (reviewer_id) REFERENCES reviewer(id)

我对仅具有唯一约束的复合索引感到满意,但我也无法弄清楚如何做到这一点。我已经能够创建一个非唯一的复合索引,但这有两个问题。一,它不是唯一的。二,列在索引中按字母顺序指定(beer_id,reviewer_id)。我想指定索引中列的顺序。

3 个答案:

答案 0 :(得分:2)

我已经实施了类似的情况,有一些不同的条件:

  1. 没有hasMany关系。
  2. 对连接类的查询由HQL
  3. 完成
  4. 使用更详细的映射
  5. 当这样实现时,mysql数据库就可以了。 (beer_id,reviewer_id)是主键。

    class Review implements Serializable {
    
        Beer beer
        Reviewer reviewer
    
        static Review get(long beerId, long reviewerId) {
            find 'from Review where beer.id=:beerId and reviewer.id=:reviewerId',
                [beerId: beerId, reviewerId: reviewerId]
        }
    
        static boolean remove(Beer beer, Reviewer reviewer, boolean flush = false) {
            Review instance = Review.findByBeerAndReviewer(beer, reviewer)
            instance ? instance.delete(flush: flush) : false
        }
        ...
    
        static mapping = {
            table "REVIEW"
            id composite: ['beer', 'reviewer']
            beer(column: "beer_ID")
            reviewer(column: "reviewer_ID")
            version false
        }
    }
    

    我不知道究竟是什么导致了您的问题,但希望这能为您提供有关问题所在的提示。

答案 1 :(得分:2)

我接受了Grails的授权,我不应该使用复合主键作为明智的建议并避免它。如果是这样,我相信解决问题的可行方法是复合唯一约束。 参考:http://grails.org/doc/1.1.x/ref/Constraints/unique.html

Jacco的答案似乎不正确,虽然它看起来非常接近正确,但这就是你如何为这个问题编写一个复合唯一约束:

static constraints = {
    beer(unique: 'reviewer')
}

如果程序员想要将3个db字段链接为唯一,那么正确的形式是:

static constraints = {
    beer(unique: ['anotherField','reviewer'])
}

看起来就像Jacco的答案一样,但是类名不会被用作约束的第一个字符串,而是使用第一个字段名。

我刚在我自己的项目应用程序中使用了这个代码结构,它似乎行为正常,另请参阅如何对单独测试的唯一约束进行单元测试: http://www.ibm.com/developerworks/java/library/j-grails10209/index.html (见清单11)

答案 2 :(得分:0)

试试这个,在您的域中查看域类:

static constraints = {
     review(unique: ['beer','reviewer'])
}

您可能需要删除该表并让Gorm重新创建它。

上述限制意味着评论必须包含啤酒/评论者组合的独特记录。在审稿人有多种啤酒的情况下仍然有很多,反之亦然,但评论是独一无二的。