Olga Bayok
Olga Bayok

Reputation: 91

Grails object references an unsaved transient instance

i have this issue when i want to save my object

My Customer

String firstName
String lastName
LocalDate dateOfBirth
CountryCode nationality

My CountryCode

  @Audited
class CountryCode implements Serializable {

  String code
  String symbolA2
  String symbolA3
  String countryName

  static constraints = {
    code size:3..3, unique: true, matches: '[0-9]+'
    symbolA2 size:2..2, nullable: false, unique: true, matches: '[A-Z]+'
    symbolA3 size:3..3, nullable: false, unique: true, matches: '[A-Z]+'
    countryName size:1..50
  }

  static mapping = {
    id generator: 'assigned', name: 'code'
  }

  def beforeValidate() {
    symbolA2 = symbolA2?.toUpperCase()
    symbolA3 = symbolA3?.toUpperCase()
  }

  @Override
  String toString() {
    return countryName
  }
}

when i try to save my object i recieve this error

Class org.hibernate.TransientObjectException Message object references an unsaved transient instance - save the transient instance before flushing: lookup.iso.CountryCode

Do you have ideas how to fix this?

Thankx

Upvotes: 4

Views: 6964

Answers (2)

ikumen
ikumen

Reputation: 11663

The specific reason for your error is because you haven't saved CountryCode before assigning it to the Customer, so Hibernate (the underlying ORM for Grails) considers it transient. Basically you do not have any GORM relationships (e.g, has*, belongsTo) defined. By defining a GORM relationship, you gain the ability to have cascade save/delete depending on how the relationships are defined.

Before simply adding hasOne or belongsTo to Customer and CountryCode respectively, you may want to consider how you are using CountryCode. Is CountryCode used as:

  1. one-to-many lookup/reference/dictionary entity where many Customers may be mapped to a particular CountryCode
  2. one-to-one unique entity where there's a unique CountryCode per Customer

To implement #1, you should define just a uni-directional relationship using belongsTo in CountryCode WITHOUT a hasOne in Customer like so:

class CountryCode {
  static belongsTo = [customer: Customer]
  ...
}

This will create a foreign key on the Customer table referencing a particular CountryCode - basically a one-to-many.

To implement #2, you should define a bi-directional relationship using belongsTo in CountryCode WITH a hasOne in Customer like so:

class Customer {
  static hasOne = [country: CountryCode]
  ..
}
class CountryCode {
  static belongsTo = [customer: Customer]
  ..
}

This will create a foreign key on the CountryCode table back to a particular Customer - basically a one-to-one mapping.

Upvotes: 2

topr
topr

Reputation: 4622

Use Grails relation convention

static hasOne = [nationality:CountryCode]

at Customer class and

static belongsTo = [customer:Customer]

at CountryCode class

Check grails docs about that, especially paragraph stating about cascade saves. If this doesn't fit your case than you need to call save() on CountryCode instance before assigning it to a Customer instance.

You can also use static embedded if apply to your case.

Another thing if you consider CountryCode as a dictionary entity, then load desired ContryCode instance from repository before assigning it to the Customer instance.

Upvotes: 2

Related Questions