Отображение Grails один-ко-многим с joinTable - PullRequest
2 голосов
/ 13 января 2011

У меня есть два предметных класса. Один - «Партнер», другой - «Клиент». Клиент может быть частью Партнера, а Партнер может иметь 1 или более Клиентов:

class Customer {
    Integer id
    String name
    static hasOne = [partner:Partner]
    static mapping = {
        partner joinTable:[name:'PartnerMap',column:'partner_id',key:'customer_id']
    }
}

class Partner {
    Integer id
    static hasMany = [customers:Customer]
    static mapping = {
        customers joinTable:[name:'PartnerMap',column:'customer_id',key:'partner_id']
    }
}

Однако всякий раз, когда я пытаюсь определить, является ли клиент частью партнера, например:

def customers = Customer.list()
customers.each {
     if (it.partner) {
          println "Partner!"
     }
}

Я получаю следующую ошибку:

org.springframework.dao.InvalidDataAccessResourceUsageException: could not execute query; SQL [select this_.customer_id as customer1_162_0_, this_.company as company162_0_, this_.display_name as display3_162_0_, this_.parent_customer_id as parent4_162_0_, this_.partner_id as partner5_162_0_, this_.server_id as server6_162_0_, this_.status as status162_0_, this_.vertical_market as vertical8_162_0_ from Customer this_]; nested exception is org.hibernate.exception.SQLGrammarException: could not execute query

Похоже, что Grails думает, что partner_id является частью запроса Customer, а не ... Он находится в таблице PartnerMap, которая должна найти customer_id, а затем получить Partner из соответствующего partner_id.

Кто-нибудь знает, что я делаю не так?

Edit: я забыл упомянуть, что я делаю это с устаревшими таблицами базы данных. Итак, у меня есть таблица Partner, Customer и PartnerMap. В PartnerMap просто есть поля customer_id и partner_id.

1 Ответ

5 голосов
/ 13 января 2011

Учитывая то, как работает 1-многие, когда вы хотите объединить стол, я думаю, что при использовании стандартной GORM невозможно сделать его двунаправленным и получить доступ к партнеру клиента. Но вы можете сопоставить таблицу соединений с классом домена и получить к ним доступ таким образом:

Заказчик:

class Customer {
   String name
   def getPartner() {
      PartnerMap.findByCustomer(this)?.partner
   }
}

Партнер:

class Partner {
   String name
   def getCustomers() {
      PartnerMap.findAllByPartner(this)*.customer
   }
}

PartnerMap:

import org.apache.commons.lang.builder.HashCodeBuilder

class PartnerMap implements Serializable {

   Partner partner
   Customer customer

   boolean equals(other) {
      if (!(other instanceof PartnerMap)) {
         return false
      }

      other.partner?.id == partner?.id &&
         other.customer?.id == customer?.id
   }

   int hashCode() {
      def builder = new HashCodeBuilder()
      if (partner) builder.append(partner.id)
      if (customer) builder.append(customer.id)
      builder.toHashCode()
   }

   static PartnerMap get(long partnerId, long customerId) {
      find 'from PartnerMap where partner.id=:partnerId and customer.id=:customerId',
         [partnerId: partnerId, customerId: customerId]
   }

   static PartnerMap create(Partner partner, Customer customer, boolean flush = false) {
      new PartnerMap(partner: partner, customer: customer).save(flush: flush, insert: true)
   }

   static boolean remove(Partner partner, Customer customer, boolean flush = false) {
      PartnerMap instance = PartnerMap.findByPartnerAndCustomer(partner, customer)
      instance ? instance.delete(flush: flush) : false
   }

   static void removeAll(Partner partner) {
      executeUpdate 'DELETE FROM PartnerMap WHERE partner=:partner', [partner: partner]
   }

   static void removeAll(Customer customer) {
      executeUpdate 'DELETE FROM PartnerMap WHERE customer=:customer', [customer: customer]
   }

   static mapping = {
      id composite: ['customer', 'partner']
      version false
      table 'PartnerMap'
   }
}

Поскольку вы не используете hasMany, вы теряете динамический метод addToXXX, но вы можете вызвать PartnerMap.create(), чтобы связать два экземпляра. Вы также теряете коллекцию и back-ref в классах домена, но я добавил служебные методы для них.

...