Проекция Грааля на арифметическое выражение с executeQuery ()? - PullRequest
2 голосов
/ 04 октября 2011

Мне нужно получить сумму всех товаров, проданных за заказ в магазине. Я запускаю sum () для выражения с помощью executeQuery (). Он работает нормально, как показано ниже, но я хотел знать, есть ли лучший, более удачный способ сделать это.

StoreService {
  static transactional = false

  def getTotalOrders(def store) {
    return Store.executeQuery("select sum(a.soldQuantity * a.soldPrice) as total 
             from OrderItem a inner join a.order b inner join b.store c 
             where c= :store", [store: store]).get(0)
  }
}

Store {
  transient storeService

  def getTotalSales() {
    storeService.getTotalSales()
  }

  static hasMany = [items: Item]
  // no hasMany to Order
}

Item {
  static belongsTo = [store: Store]
  // no hasMany to OrderItem
}


Order {
  static hasMany = [orderItems: OrderItem]
  static belongsTo = [store: Store]
}


OrderItem {

  BigDecimal soldPrice
  Integer soldQuantity

  static belongsTo = [order: Order, item: Item]

}

Я думаю, что с Criteria () было бы легче читать, но я не мог понять, как это сделать с помощью выражений в sum () по понятным причинам.

projections {
  sum("soldPrice * soldQuantity")
}

Спасибо

Ответы [ 4 ]

10 голосов
/ 04 октября 2011

Существует два варианта:

Параметр 1

Вы можете добавить отображение формулы в свой класс домена, а затем запросить его напрямую.

OrderItem {
  BigDecimal soldPrice
  Integer soldQuantity
  BigDecimal totalPrice

  static mapping = {
    totalPrice formula: "sold_price * sold_quantity"
  }

  static belongsTo = [order: Order, item: Item]

}

Теперь ваш запрос критерия может содержать только

projections {
    sum("totalPrice")
}

Мало того, вы можете запросить его с помощью динамического поиска OrderItem.findAllByTotalPriceGreaterThan(20.00), а также с простым доступом println "The final price is ${orderInstance.totalPrice}.Мы находим это действительно изящным, однако бывают случаи, когда вы хотите получить totalPrice до того, как OrderItem будет сохранен, поэтому мы обычно пишем простой (не сухой) метод получения

BigDecimal getTotalPrice() {
    totalPrice ?: (soldPrice && soldQuantity) ? soldPrice * soldQuantity : null
}

Но вам нужны только такие вещиесли вам требуется totalPrice до его сохранения.

Вариант 2

Перед отображениями формул мы обычно выпадали в Hibernate Criteria API и использовали проекцию sqlProjection как частьнашего критерия запроса.

projections {
    addProjectionToList(Projections.sqlProjection(
            "sum(sold_price * sold_quantity) as totalPrice",
            ["totalPrice"] as String[], 
            [Hibernate.LONG] as Type[],
        ), "sumProjection")
 }

Примечание

Я думаю, что важно отметить, что как в формуле, так и в проекции sql используйте имена столбцов вбаза данных и синтаксис вашей конкретной базы данных.

1 голос
/ 31 мая 2013

Начиная с Grails 2.2, проекции SQL поддерживаются без необходимости перехода к API Hibernate Criteria. Обратите внимание, что отображение формул все еще может быть более желательным, но с этим вы можете напрямую реализовать проекцию типа sum ('soldPrice * soldQuantity') в соответствии с вашим вопросом.

http://grails.org/doc/latest/guide/single.html#criteria

1 голос
/ 04 октября 2011

Я бы попытался добавить временное производное свойство total к OrderItem и использовать sum() для него.

0 голосов
/ 15 июня 2017

Попробуйте SQL Projection

projections {
  sqlProjection 'sum("soldPrice * soldQuantity") as total', 'total', StandardBasicTypes.DOUBLE
}

Для более подробной информации http://docs.grails.org/2.5.6/guide/GORM.html#criteria

...