How to establish uniqueness at the database level for the one-to-many association?

My problem is simple, but I could not find the GORM syntax for this.

Consider the following class:

class Article {
  String text

  static hasMany = [tags: String]

  static constraints= {
    tags(unique: true) //NOT WORKING
  }

}

I want to have one unique tag name in each article defined in my restrictions, but I cannot do this with the above syntax. Obviously, I need something like in the DB schema:

create table article_tags (article_id bigint, tags_string varchar(255), unique (article_id , tags_string))

How can i do this?

PS: I am also stuck to set the minimum and maximum tag size limits

+3
source share
5 answers

FYI, you can also use a custom validator in domain classes:

    static constraints = {
    tags(validator: { 
        def valid = tags == tags.unique()
        if (!valid) errors.rejectValue(
            "tags", "i18n.message.code", "default message")
        return valid
    })

DDL, grails-app/conf/hibernate/hibernate.cfg. XML:

<hibernate-mapping>
    <database-object>
        <create>
        ALTER TABLE article_tags
        ADD CONSTRAINT article_tags_unique_constraint 
        UNIQUE(article_id, tags_string);
    </create>
        <drop>
        ALTER TABLE article_tags 
        DROP CONSTRAINT article_tags_unique_constraint;
    </drop>
    </database-object>
</hibernate-mapping>
+5

joinTable, , unique, .

, , :

  • SQL, . - (, Liquibase), .

  • Set. Hibernate, - .

    class Article {
        static hasMany = [tags: String]
        Set<String> tags = new HashSet<String>()
    }
    

(Tag) " ", unique , constraints. . :

class Article {
    static hasMany = [articleTags: ArticleTag]
}

class Tag {
    static hasMany = [articleTags: ArticleTag]
}

class ArticleTag {
    Article article
    Tag tag
    static constraints = {
        tag(unique: article)
    }
}

" " . , . ( Membership ArticleTag ).

, , GORM, , .

+2

EDIT: , unique(article_id , tags_id). , Article . - .

(. Grails ). " " GORM. unique nullable , , .

, dbCreate="create" , . Article PostgreSQL :

CREATE TABLE article_tags
(
  article_id bigint NOT NULL,
  tags_string character varying(255),
  CONSTRAINT fkd626473e45ef9ffb FOREIGN KEY (article_id)
      REFERENCES article (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT article0_tags_article0_id_key UNIQUE (article_id)
)
WITH (
  OIDS=FALSE
);

, tags_string .

, "" , .

, - Tag TagHolder, , - Article API.

TagHolder:

class TagHolder {
    String tag

    static constraints = {
        tag(unique:true, nullable:false, 
            blank:false, size:2..255)
    }
}

Article:

class Article {
    String text

    static hasMany = [tagHolders: TagHolder]
}

API, String[] getTags(), void setTags(String[]. , , , new Article(text: "text", tags: ["foo", "bar"]). addToTags(String), GORM " ".

class Article {
    String text

    static hasMany = [tagHolders: TagHolder]

    String[] getTags() { 
        tagHolders*.tag
    }

    void setTags(String[] tags) {
        tagHolders = tags.collect { new TagHolder(tag: it) }
    } 

    {
        this.metaClass.addToTags = { String tag ->
            tagHolders = tagHolders ?: []
            tagHolders << new TagHolder(tag: tag)
        }
    }
}

, . , JOIN. , .

, :

class ArticleTests extends GroovyTestCase {
    void testUniqueTags_ShouldFail() {
        shouldFail { 
            def tags = ["foo", "foo"] // tags not unique
            def article = new Article(text: "text", tags: tags)
            assert ! article.validate()
            article.save()
        }
    }

    void testUniqueTags() {     
        def tags = ["foo", "bar"]
        def article = new Article(text: "text", tags: tags)
        assert article.validate()
        article.save()
        assert article.tags.size() == 2
        assert TagHolder.list().size() == 2
    }

    void testTagSize_ShouldFail() {
        shouldFail { 
            def tags = ["f", "b"] // tags too small
            def article = new Article(text: "text", tags: tags)
            assert ! article.validate()
            article.save()
        }
    }

    void testTagSize() {        
        def tags = ["foo", "bar"]
        def article = new Article(text: "text", tags: tags)
        assert article.validate()
        article.save()
        assert article.tags.size() == 2
        assert TagHolder.list().size() == 2
    }

    void testAddTo() {
        def article = new Article(text: "text")
        article.addToTags("foo")
        article.addToTags("bar")
        assert article.validate()
        article.save()
        assert article.tags.size() == 2
        assert TagHolder.list().size() == 2
    }
}
+1

, , - . , GORM .

0

Source: https://habr.com/ru/post/1771906/


All Articles