grails: show field of object in gsp - sql

In my grails project I create instances of an object called Patient, that has got a field city.
class Patient {
String name;
String surname;
String cf;
String address;
String cap;
String city;
String province;
String country;
String phone_1;
String phone_2;
String email;
String vat;
}
When I create a Patient, I store city by its id, but I want that, in show() and list() methods, I see the name of the related city.
The Cities domain class is linked to a table in my db as follows
class Cities {
String cityName;
String capOfCity;
String provinceOfCity;
static constraints = {
}
static mapping = {
table 's_cap'
id column: 'idcap'
cityName column: 'comune'
capOfCity column: 'cap'
provinceOfCity column: 'prov'
version false
}
}
I suppose that I must perform a query to db to get its name by id, but how can I do it in gsp?

With your current approach you can do
def show(){
// look up your patient object
def patient = Patient.get(123)
def patientCityObject = Cities.findByCityName(patient.city)
[patientCityObject: patientCityObject ]
}
GSP:
<p>${patientCityObject.cityName}</p>
However,
If you define the association between your domains then Grails will load your city when you are accessing it. To access you city object associated with Patient, you can define it as follow:
class Patient {
...
Cities city;
...
}
Then when you have the patient object, you can easily access its property city.
def patient = Patient.get(123)
patient.city.cityName
This will give you the city object associated with your patient. Then you can pass that into your GSP and use it.
To learn more about GORM and object relation you can read Object Relational Mapping

Related

select model B with model A column name condition in laravel model

I have two models with different name and columns but the purpose/data of the two models is the same, namely, it contains the employee's name, here the model
Employee
name
code
country
city
John
A1
USA
NYC
Doe
A2
USA
LA
New_Employee
v_fullname
v_code
v_country
v_city
Mark
ZZ1
USA
LS
Zuc
FF2
USA
LS
as you can see the column name is different but the purpose is identical. I want to select data from New_Employee but use column name from Employee, so the query will look like this
SELECT v_fullname as name, v_code as code, v_country as country, v_city as city
FROM New_Employee
WHERE name = 'Mark'
Sorry if my explanation is hard to understand, but here's the code I have tried
SyncEmployee model (this model is like a bridge connecting employee and new_employee model)
<?php
namespace App\Models;
use App\Models\Employee;
use App\Models\NewEmployee;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class SyncEmployee extends Model
{
use HasFactory;
protected $connection = 'mysql_2';
public const TABLE_NAME = 'new_employee';
public function index()
{
$data = NewEmployee::select('v_fullname as name, v_code as code, v_country as country, v_city as city')->get();
return view('view_name', compact('data'));
}
}
I thought with that code when I call SyncEmployee::where('code', '=', 'ZZ1') from controller, the result will
name
code
country
city
Mark
ZZ1
USA
LS
*The data is from New_Employee but the column name using Employee
You could attempt to use the ability to hide or append attributes at serialization to do most of the work for you. You would need to define accessors and mutators and define what is 'hidden' and 'appended' for serialization:
use Illuminate\Database\Eloquent\Casts\Attribute;
class NewEmployee extends Model
{
...
protected $table = 'new_employee';
protected $hidden = [
...
'v_fullname',
'v_code',
'v_country',
'v_city',
];
protected $appends = [
...
'name',
'code',
'country',
'city',
];
protected function name(): Attribute
{
return Attribute::make(
get: fn () => $this->attributes['v_fullname'] ?? null,
set: fn ($v) => $this->attributes['v_fullname'] = $v
);
}
...
}
If you are not using the Model's data after serialization you can still access these fields:
// will hit the accessor
$newEmployee->code;
// will hit the mutator
$newEmployee->code = 'blah';
Laravel 9.x Docs - Eloquent: Mutators and Casting - Accessors & Mutators
Laravel 9.x Docs - Eloquent: Serialization - Hiding Attributes From JSON
Laravel 9.x Docs - Eloquent: Serialization - Appending Values to JSON

Hibernate createNativeQuery returns duplicate rows

I have 2 database tables Customer and Items with 1 -> many relation. To fetch data from database i am using the following query.
select customer.id, customer.name, items.itemName, items.itemPrice from testdb.customer INNER JOIN items ON items.customer_Id = customer.id
I have an entity class Customers
#Entity
public class Customer{
#Id
private int id;
#Column
private String name;
#Column
private String itemName;
#Column
private int itemPrice;
public Customer() {}
//Getter and setter are here
.......
}
in Service class i have the following code.
#GET #Path("/getCustomerInfo")
#Produces(MediaType.APPLICATION_JSON)
public List getCustomerInfo() {
CustomerDao dao = new CustomerDao();
return dao.getBuildingsCustomerInfo();
}
in my DAO class i have the following code
public List<Customer> getCustomerInfo(){
Session session = SessionUtil.getSession();
String queryString = "the above mentioned query";
List<Customer> customerInfo = session.createNativeQuery(queryString, Customer.class) ;
session.close();
return customerInfo;
}
I am getting the following JSON response from the service
[id:1, name:"Alfred", itemName:"jeans", itemprice:10],[id:1, name:"Alfred", itemName:"jeans", itemprice:10],[id:2, name:"James", itemName:"watch", itemPrice:20 ],[id:2, name:"James", itemName:"watch", itemPrice:20 ], [id:2, name:"James", itemName:"watch", itemPrice:20 ]
The number of results are 5 which is correct But 2nd result is a copy of 1st, 4th and 5th are copies of 3rd. In 2nd, 4th and 5th results the itemName and the itemPrice should be different.
if I use createSQLQuery(queryString); instead of createNativeQuery(queryString, Customer.class); I am getting the correct result but without entity attribut names.
[1, "Alfred", "jeans", 10],[1, "Alfred", "shirt", 15],[2, "James", "watch", 20], [2, "James", "coffee", 25], [2, "James", "drinks", 30]
I have seen number of articles but could not find the solution. I have to use createNativeQuery() not createSQLQuery() because I need to map the entity class attributes. Please let me know if i am doing something wrong.
Your data structure is wrong on the Java side and not corresponding to the database relation. In the relation you describe you need to have a list of items:
#Entity
public class Customer implements Serializable {
// ... the fields you have so far
// assuming the parent field on the other side is called customer
// you may also want to set the cascade and orphanRemoval properties of the annotation
#OneToMany(mappedBy = "customer")
#JsonManagedReference // assuming you're using Jackson databind JSON
private List<Item> items;
}
And on the Item side:
#Entity
public class Item implements Serializable {
#Id
private int id;
#JsonBackReference
#ManyToOne
#JoinColumn(name = "customer_Id")
private Customer customer;
}
Then if you really the JSON data strucutred that way, you need a third Entity class to use as a ResultSetMapping.
#Entity
#SqlResultSetMapping(
name = "CustomerItem",
entities = #EntityResult(entityClass = CustomerItem.class)
)
#NamedNativeQueries({
#NamedNativeQuery(
name = "CustomerItem.getAll",
resultSetMapping = "CustomerItem"
query = "select customer.id as cid, items.id as iid, customer.name,"
+ " items.itemName, items.itemPrice from testdb.customer INNER JOIN"
+ " items ON items.customer_Id = customer.id"
)
})
public class CustomerItem implements Serializable {
#Id
private int cid;
#Id
private int iid;
#Column
private String name;
#Column
private String itemName;
#Column
private int itemPrice;
... getters and setters
}
Then you can use the native query in named variant, which should offer some slight optimizations.
List<CustomerItem> lst = em.createNamedQuery("CustomerItem.getAll", CustomerItem.class)
.getResultList();
The use of #SqlResultSetMapping is so that the returned entities are not monitored for changes, but you can still use the defined entity for the result. I believe that by JPA specification it should also work without it, but in Hibernate it doesn't. Could be a bug, or a planned, but not implemented feature, or I could just be misinterpreting the JPA usage, but this workaround does work with Hibernate 5+.
Not sure about the exact reason behind duplicates but SELECT DISTINCT will solve your issue as it will take only distinct records.
Refer using-distinct-in-jpa
I solve this issue by using #SqlResultSetMapping

groovy oracle result capital column name issue

In Groovy to set a bean you just need to give the GroovyRowResult while creating object.
Consider below People.groovy bean:
class People {
String name
int age
}
My sql query:
select * from People -- returns name and age of people
the GroovyRowResult is returned with column names (keys) in capitals like it:[NAME:"Alex", AGE: 21].
So when I try to set the bean like below:
le.rows(sqlQuery).each {
People p = new People(it)
}
I receive the Exception:
groovy.lang.MissingPropertyException: No such property: NAME for class: People. Possible solutions: name
I guess I can modify sql query to include double quotes on the alias, but have you guys handled it any different?
The rows() method returns a List<GroovyRowResult> where GroovyRowResult implements Map and then you can apply collectEntries to transform it, so that the keys are lowercase and you can use the resulting map:
sql.rows('select * from people').each {
People p = new People(it.collectEntries { k,v -> [k.toLowerCase(), v] })
println p.name
println p.age
}

JasperReports for grails: Using HashMap as Model?

Imagine I have two classes in Groovy that look like that:
class Person {
int id;
String name;
}
class Item {
int id;
int price;
}
Now it would be simple to create a JasperReport listing all persons' names using the following SQL:
SELECT name FROM Person
Also, it would be easy to pass a Model from which the list should be created:
def p = Person.withCriteria {
eq('name','SomeGuy')
}
chain(controller:'jasper',action:'index',model:[data:p],params:params)
But what I want to do is to use the following query:
SELECT name, (SELECT sum(i.price) FROM Item f WHERE f.id=p.id) as priceSum FROM Person p
And now this is the part where I don't know how to go on: How can I pass any Model to the jasperReport? I can't just use
def p = Person.withCriteria {
eq('name','SomeGuy')
}
because then, the priceSum attribute would be missing.
What I would like to do is something like this:
def l = ['name':'SomeGuy','priceSum':'5000']
chain(controller:'jasper',action:'index',model:[data:l],params:params)
But this doesn't work either, it gives me:
Message: Cannot get property 'name' on null object
Caused by: java.lang.NullPointerException: Cannot get property 'name' on null object
Is there anything simliar to this that would work?

NHibernate does not filter data base on COORECT TYPE of meta data

I have an interface (IContactable) which is realizing by 3 classes : Person, Department, RestUnit
public interface IContactable
{
Contact Contact { get; set; }
string Title { get; }
int? Id { get; set; }
}
public class Person:IContactable
public class Department:IContactable
public class RestUnit:IContactable
There is another class, Contact, which should maintain which one of these objects are the owner of the contact entity.
A part of Contact mapping which does the job is:
ReferencesAny(p => p.Contactable)
.EntityTypeColumn("ContactableType")
.EntityIdentifierColumn("ContactableId")
.IdentityType<int>()
.AddMetaValue<Person>("Person")
.AddMetaValue<Department>("Department")
.AddMetaValue<RestUnit>("RestUnit");
So that Contact records in database would be like (The types are being saved as string):
X Y ContactableType ContactableId
... ... Person 123
... ... Person 124
... ... Department 59879
... ... RestUnit 65
... ... Person 3333
... ... Department 35564
Everything works just fine but filtering data. When I want to get some particular Contacts, say with Department type, I would write something like :
var contacts = Repository<Contact>.Find(p=>p is Department);
Nhibernate tries to filter data based on ContactableType field with an integer value but the ContactableType column is nvarchar
Generated query by NHibernate :
select .......... from contact.[Contact] where ContactableType=1
Expected query:
select .......... from contact.[Contact] where ContactableType='Department'
So NHibernate kinda using a wrong type. int instead of string.
I think NH is using the index of the object in list which AddMetaValue("Department") has added department type into...
I hope the explanation would be clear enough
I'm using NH3....
any idea?
Have you tried to add an extra line:
ReferencesAny(p => p.Contactable)
.MetaType<string>()