I'm trying to learn Grails but am still pretty much on beginner level.
I made a tiny application, where you can basically add events, and people can write reviews about them and rate them.
So I have an eventController and reviewController. The rating is just an Integer in a review. But now I want to show an overall rating for an event. So the events rating should be the average value of the corresponding ratings value.
This is my event domain code where the rating is initially set, I left out the constraints and toString:
class Event {
Double dRating = 2
static hasMany = [ratings:Rating]
}
The controller is simply:
class EventController {
def scaffold = Event
}
The rating domain file:
class Rating {
String comment
java.util.Date date = new java.util.Date()
Integer rating
Event event
}
and the Rating Controller is:
class RatingController {
def scaffold = Rating
}
Hope I didn't make mistakes, I had to translate variable names so they're understandable.
I'm guessing that where dRating is set, I could somehow add some calculation, but I don't even know how to access the values of the rating, and everything I try ends in lots of errors and having to restart the app again and again. I tried adding calculations in the controller, but there I don't know how to get the value into the database. So where do I actually put the logic, and how do I access the values?
If any other file is important, please tell me.
Hoping to get some hints on how to start doing this, I didn't think it would be this hard.
At first I would recommend start reading grails doc. Later from your question it is not much clear what you are asking a there could be several places or possibilities of setting up the value in domain field and persist it to database. I'm telling all of these which are known to me:
If it is generalised calculation that needs to be applied to your dRating field, then create a setter with standard bean naming convention and do this there. For example, you want to find percentage from say 1000 and then add it to dRating
class Event {
static hasMany = [ratings:Rating]
Double dRating
void setDRating(Double value){
this.dRating = value * 100/1000 // alternatively value /10
}
}
Do it in commandObject: If you don't want to put certain calculations and validation in domain then put these in command objects. See this. You can at any point of time assign values from command object to domain object by .properties binding mechanism. For example,
yourDomainObject.properties = yourcommandObjectObject.properties
Remember properties having same name would be binded.
Do it in service: You can do your calculations in service method, inject that service into your controller and call that method to perform calculations and even to persist to db as well. Remember services are by default transactional.
Hope it helps!
Related
I just wasted half a day trying to figure this out, reading about some workarounds, and thinking "it can't be that bad - there must be a straightforward to do edit a collection in Grails, whethere using scaffolded views or my own."
Let's say I have this domain object:
class TreeGroup {
String name
List<Tree> trees
static hasMany = ['trees': MyTree]
}
Just to explain the choice of data structure - I need my records to be unique, but in the order I set. That's why I chose List, AFAIK one cannot rely on order in a Set. So there are 2 pieces to this question - 1) how to remove from any Collection, for example a Set, 2) is List the best replacement for Set in this context (preserving order).
I want to be able to create a group record with no trees in it and make 4 updates:
edit/save
edit the group record to reference 2 trees A and B
add another tree C
remove A
remove B and C
And obviously, I want the desired state after every step. Currently though, I can only add records, and if I even edit/save to list, the list elements are added to it again.
I am using the multiple select tag for this. It looks like this:
<g:select name="trees" from="${allTrees}" optionKey="id"
multiple="true" class="many-to-many"
value="${trees ? trees*.id : treeGroupInstance?.trees*.id}" />
and that's fine, in the sense that it generates an HTTP header with these variables on update:
_method:PUT
version:19
name:d5
trees:1
_action_update:Update
But the data binder only adds new elements, it never lets you edit a list.
What is the cleanest way to do it ? Is it me, not reading something obvious, or is this a design flaw of grails data binding (and of so, when/how will it be fixed) ?
Is there a way perhaps via a hidden HTTP parameter to clear the list before (re)adding elements ?
Thanks
I ended up doing this:
private repopulate(def domainObject, String propertyName, Class domainKlaz) {
if (params[propertyName] != null) {
domainObject[propertyName].clear()
domainObject[propertyName].addAll(
params[propertyName].collect { domainKlaz.get(it) }
)
}
}
and I am calling it in update controller method before save(), for every collection. OMG how ugly.
I have two object, a room type and a reservation. Simplified they are:
class Room {
String description
int quantity
}
class Reservation {
String who
Room room
}
I want to query for all rooms along with the number of rooms available for each type. In SQL this does what I want:
select id, quantity, occupied, quantity-coalesce(occupied, 0) as available
from room left join(select room_id, count(room_id) as occupied from reservation)
on id = room_id;
I'm not getting anywhere trying to work out how to do this with HQL.
I'd appreciate any pointers since it seems like I'm missing something fairly fundamental in either HQL or GORM.
The problem here is your trying to represent fields that are not your domain classes like available and occupied. Trying to get HQL\GORM to do this can be a bit a little frustrating, but not impossible. I think you have a couple options here...
1.) Build your domain classes so that there easier to use. Maybe your Room needs to know about it's Reservations via a mapping table or, perhaps write what you want the code to look like and then adjust the design.
For example. Maybe you want your code to look like this...
RoomReservation.queryAllByRoomAndDateBetween(room, arrivalDate, departureDate);
Then you would implement it like this...
class RoomReservation{
...
def queryAllByRoomAndDateBetween(def room, Date arrivalDate, Date departureDate){
return RoomReservation.withCriteria {
eq('room', room)
and {
between('departureDate', arrivalDate, departureDate)
}
}
}
2.) My second thought is... It's okay to use the database for what it's good for. Sometimes using sql in you code is simply the most effective way to do something. Just do it in moderation and keep it centralized and unit tested. I don't suggest you use this approach because you query isn't that complex, but it is an option. I use stored procedures for things like 'dashboard view's' that query millions of objects for summary data.
class Room{
...
def queryReservations(){
def sql = new Sql(dataSoruce);
return sql.call("{call GetReservations(?)}", [this.id]) //<-- stored procedure.
}
}
I'm not sure how you can describe a left join with a subquery in HQL. INn any case you can easily execute raw SQL in grails too, if HQL is not expressive enough:
in your service, inject the dataSource and create a groovy.sql.Sql instance
def dataSource
[...]
def sql= new Sql(dataSource)
sql.eachRow("...."){row->
[...]
}
I know it's very annoying when people try to patronize you into their way of thinking when you ask a question, instead of answering your question or just shut up, but in my opinion, this query is sufficiently complex that I would create a concept for this number in my data structure, perhaps an Availability table associated to the Room, which would keep count not only of the quantity but also of the occupied value.
This is instead of computing it every time you need it.
Just my $.02 just ignore it if it annoys you.
It's a bit difficult for me to put my questions in words, but I'll try.
I have two entities. One is called Product the other Sale. Each product has field definining the number of available items of this product. Each sale has a field stating the number of sold items of one product. Product to Sale is a OneToMany-Relationship.
Now if I want to find out if a product has sold out, I need to create a function which substracts the total number of sold items from the initial availability number of the product. Something like function getAvailableQuantity().
My question is: Where do I place this method?
I am tempted to put it in the Product Repository - but since this method needs to access the Sales entity this is against Dependency Injection. However, placing it in the controller seems like an unnecessary detour as I am losing the possibility of calling {{ product.getAvailableQuantity }} in Twig templates.
What is the way to go?
Thanks for any help!
I would suggest subtracting the sold items right away from Product::available_items. This would resolve the issue right away, because Product::available_items would always reflect the number of available items.
Method no. 1
Subtract Sale::quantity from Product right away.
public function setProduct(ProductInterface $product)
{
$new_count = $product->getAvailableItems() - $this->getQuantity();
$product->setAvailableItems($new_count);
$this->product = $product;
}
You'd also have to do the subtracting in all the controllers that might change the available item count.
Method no. 2
Personally, I would actually favor this method over the first one, because it keeps the logic in a single place and generally results in shorter controllers. In addition, my entities are usually long enough without all the domain logic.
Assuming Sale has a reference to a Product, I'd put the logic into a service (an entity-specific entitymanager, e.g UserManager. It'd be called SaleManager in our case). The method in it would look something similar to:
public function updateSale(SaleInterface $sale, $flush = true)
{
$product = $sale->getProduct();
$new_count = $product->getAvailableItems() - $sale->getQuantity();
if ($new_count < 0) {
throw new NegativeQuantityException();
}
$product->setAvailableItems($new_count);
$this->em->persist($sale);
if (true === $flush) {
$this->em->flush();
}
}
I didn't touch the issue of what would happen if you were to remove a Sale from a Product or switch a Product in a sale, but you must certainly consider this as well.
Where do I place this method?
Consider creating a ProductSalesManager service into which you inject the entity manager. From a controller you would have something like:
$productSalesManager = $this->get(product_sales.manager);
$products = $productSalesManager->getProductsWithAvailableQuantity();
Now you can put your logic in the manager without worrying about which repository it happens to be in. It also decouples your controller from Doctrine itself.
And I'm not so sure maintaining current inventory in the product itself is such a good idea but that is really up to you.
As the available quantity bellows to the Product, I think the work has to be done by the Product Entity.
If you use Doctrine, it has generated the function addSale in your Product Entity ( the name depend on how you define the relation). I should change this function to make the calculation.
Assuming the field in your product entity is named available_quantity and the field in your Sale Entity is named items_number:
public function addSale ( $sale )
{
$this->setAvailableQuantity($this->getAvailableQuantity() - $sale->getItemsNumber());
$this->sales[] = $sale;
}
Then in your controller you add the sale to the product:
// get the product
$product = $this->getDoctrine()
->getRepository('AcmeStoreBundle:Product')
->find($id);
// build your Sale object
$sale = new Sale();
...
// add it to the product
$product->addSale($sale);
// save all
$em = $this->getDoctrine()->getEntityManager();
$em->persist($sale);
$em->persist($product);
$em->flush();
In your template you can get the available quantity of your product:
{{ product.availableQuantity }}
I have a domain class which will have many children. Related to this other post of mine: Grails: how to structure transactions when I want to continue validating even after the transaction has already failed I want to create an instance of the parent class (MikeyJob), but NOT save it. Then make a bunch of children, and only if the children validate, save the parent and all the children.
This is all fine and good, but MikeyJob 's need a job number and this number must be unique. This is confusing me because there will be lots of "maybe it will get saved" MikeyJobs floating around in different sessions.
This is my thought:
import java.util.Random
Class MikeyJob{
BigInteger jobNumber
def beforeInsert() = {
//this is where I think I need help
Random rand = new Random()
BigInteger max = 99999999
BigInteger randomInt = rand.nextInt(max)
MikeyJob.withSession{
while(randomInt<9999999 || MikeyJob.findByJobNumber(randomInt)){
randomInt = rand.nextInt(max)
}
}
this.jobNumber = randomInt
}
static hasMany=[jobItems:JobItem]
static constraints = {
jobNumber(nullable:true)
}
}
Class JobItem{
String importantStuff
}
So I have a service that basically goes like this:
Class JobMakerService{
def makeAJob(def bigMessyList){
def someNewJob = new MikeyJob() /NOT SAVED
def validItems = []
def invalidItems = []
bigMessyList.each{
def jobItem = //pseudo code to get a job item out of messy list
//also not saved
if(jobItem.validate())validItems.add jobItem
else invalidItems.add jobItem
}
if(invalidItems = []){
someNewJob.save()
validItems.each{
it.save()
}
} else def errorHandling = 1/0
}
}
This seems to be working, but is there a better way?
Does it really need to be random? Or just unique? Getting a "random" number can't really guarantee that it is unique across everything or even across time.
First thought that comes to mind is to have a singleton type object that just adds 1 to the previous number (or use a database sequence). Don't set it until you are truly trying to save the whole tree. Your singleton could seed itself with the largest persisted job number + 1.
I have also used just a timestamp string, can make sure it is unique by adding a session unique value. ie.. user_id + "-" + new Date().time
EDIT:
Beans declared in Spring (grails) are Singletons by default (one instance for the container, not the Singleton Pattern.) So every time you autowire / inject a bean, it is the same instance throughout the system. Then you throw a synchronized method to get the next value in there. You can wire the bean up to grab it's seed (starting value) from the largest persisted (assigned) value from the database when the container starts up.
Using a database sequence is a bit different, as it relies on the underlying database to assign the value, but it would do the same thing. You should be able to define the field in the domain object to auto assign the value given by a sequence.
Look at http://mycodesnippets.com/2010/03/30/sequence-generation-with-gorm/ But for your scenario, you would want the generator on your jobNumber field. (Not 100% sure that will work though, never tried on any field except id)
I have a domain class which has two dates in it and I want one of them populated with the current time when a record is created for the object, like a create timestamp...
class Contact {
Date initiatedDate
Date acceptedDate
}
Is it sufficient just to new a Date object on one of them and make the other nullable until such a time as I need to fill it, sort of like this...
class Contact {
static constraints =
{
acceptedDate(nullable:true)
}
Date initiatedDate = new Date()
Date acceptedDate
}
I'm experimenting, but I would like to know whether this is the right way to go about it or whether there is something more Grailsy or GORMy I should do in, say, an init function or by tweaking the domain object definition to have one by default, like it does an id and version.
Thanks
What you've written should work but you can use the GORM auto-timestamping feature by simply adding a field:
class Contact {
Date dateCreated
}
If you want to keep your own names for the fields the same grails docs also show you how to use GORM events to set fields on save or update.
HTH