I am new to grails and implementing one-to-one relationship in grails and trying to query on tables and not sure on how to represent one-to-one relationship in domain classes and query the results.
I have two tables
car(car_id number primary key,name varchar2(255))
engine(eng_id number primary key,name varchar2(255),car_id number (foreign key to car_id))
Domain Classes:
class Car {
..
static hasOne = [engine: Engine]
}
class Engine {
Car car
static belongsTo = [car : Car]
}
is the above one-to-ne relationship in domain class correct??
i need to query to get all the cars which have engines,should i use criteria query api or use HQL??
Any help appreciated.
class Engine {
//Car car
static belongsTo = [car : Car]
}
Just delete Car car and all be correct. For now u have 2 links to class Car in Engine
For a true one-to-one relationship use the hasOne property on the owning side e.g. Car:
class Car {
..
static hasOne = [engine: Engine]
}
class Engine {
Car car
static constraints = [
car unique: true
}
A good practice is to add a unique constrain on one side of the relationship. Click here to read the documentation.
Related
I have sample workers table structure:
I have two type of workers: company workers and company branches workers. Type field can be only: 1 or 2. 1 - is company worker and 2 - is branch worker. How Now I can't write correct relationships method to get user company type (branch or company). Or I must create 2 tables (company_workers_table and company_branch_workers_table) for correctly write eloquent relationships?
You're looking for a polymorphic relationship:
https://laravel.com/docs/5.6/eloquent-relationships#polymorphic-relations
You want to set up your workers with two columns instead of just the type one, lets call this relation workplace. Your workers table would have workplace_id and workplace_type columns. The type columns holds the class of the related model (ie. App/Company) and your id column holds the ID of the related model, so the worker could be related to either a company or a company branch.
Your models will look something like this:
class Worker extends Model
{
public function workplace()
{
return $this->morphTo();
}
}
class Company extends Model
{
public function workers()
{
return $this->morphMany('App\Worker', 'workplace');
}
}
class Branch extends Model
{
public function workers()
{
return $this->morphMany('App\Worker', 'workplace');
}
}
This is my first post, so hi everybody! :)
I have a question regarding a schema of my database. I'm writing RESTful application using Spring. The idea is to allow user to create his own diet based on products stored in DB.
So I came to creating entity Meal, which should consist of Products and amount of those products. It seems like natural way to have something like this is using Map. Problem is, that as I have read there is a problem with mapping such class to JSON Object, which I would like to send to clients browser. My other idea was to store List of objects like ProductWithQuantity instead of such map, but I'm a little worried that DB would be quickly flooded by entries like 1 glass of milk, 2 glasses of milk, 1.1243 glasses of milk and so on.
So my question is - do you have any better idea for the schema for such purpose? ;)
I would define an entity Meal which has a oneToMany relation to an entity Product, this product has properties like 'name', 'amount' and 'unit' and 'price' or something like that. Unit can be "gramm", "liter" and so on.
I might suggest a Meal with many servings, each serving being of a single product. Products like Milk or Hamburg are likely to have nutritional information, while a Meal will have many servings of different products. Serving would essentially be a relational table between Mean and Product, but with additional information like serving size.
#Entity
Class Meal {
#Id
Integer Id;
#OneToMany(mappedBy="meal")
List<Serving> servings;
}
#Entity
Class Serving {
#Id
Integer Id;
#OneToOne
Meal meal;
#OneToOne
Product product;
#Basic
Long servingCount;
}
#Entity
Class Product {
#Id
Integer Id;
#Basic
String simpleName;
#Basic
Integer caloriesPerServing;
..
}
What is the best way to model data for a job website which has the following elements:
Two types of user accounts: JobSeekers and Employers
Employers can create JobPost entities.
Each JobSeeker can create a Resume entity, and many JobApplication entities.
JobSeekers can create a JobApplication entity which is related to a JobPost entity.
A JobPost entity may receive many JobApplication entities.
A JobSeeker may only create one JobApplication entity per JobPost entity.
A Resume contains one or more instances of Education, Experience, using ndb.StructuredProperty(repeated = True).
Each Education contains the following ndb.StringProperty fields: institution, certification, area_of_study
While each Experience contains: workplace, job_title.
Here is a skeleton model that meets your requirements:
class Employer(ndb.Model):
user = ndb.UserProperty()
class JobPost(ndb.Model):
employer = ndb.KeyProperty(kind=Employer)
class JobSeeker(ndb.Model):
user = ndb.UserProperty()
def apply(self, job_post):
if JobApplication.query(JobApplication.job_seeker == self.key,
JobApplication.job_post == job_post).count(1) == 1:
raise Exception("Already applied for this position")
...
class Resume(ndb.Model):
job_seeker = ndb.KeyProperty(JobSeeker)
education = ndb.JsonProperty()
experience = ndb.JsonProperty()
class JobApplication(ndb.Model):
job_seeker = ndb.KeyProperty(JobSeeker)
job_post = ndb.KeyProperty(JobPost)
Notes:
Employer and JobSeeker have the built-in UserProperty to identify and allow them to login.
Resume uses JsonProperty for education and experience to allow for more fields in the future. You can assign a Python dictionary to this field, for example
resume.education = {'institution': 'name', 'certification': 'certificate', 'area_of_study': 'major', 'year_graduated': 2013, ...}
(I have personally found StructuredProperty to be more pain than gain, and I avoid it now.)
Limiting a JobSeeker to only one JobApplication can be done with the method apply() which checks the JobApplication table for existing applications.
The structure of concerning tables is as follows (MySQL):
//Table Name : team
tid PK
team_name (varchar)
//Table Name : fixture
fid PK
home_team_id FK |_ both referenced to 'tid' from 'team' table
away_team_id FK |
My aim is to retrieve the team names. Considering this structure, I think I'll have to retrieve home_team_id and away_team_id and then do something like
Fixture::where('tid','=',$home_team_id)->get();
My question is, is this the correct way to accomplish what I aim to do?
and
should this be done from the controller? (if so, then I'll have to do two queries from same function)
First, rather than having your primary keys be tid and fid, just keep them both as id. This is not only best practice, but will allow you to more easily use Laravel's Eloquent ORM as it by default assumes your primary key column is named id.
Second thing, make sure your table names are in plural form. Although this is not necessary, the example I'm about to give is using Laravel defaults, and Laravel assumes they are in plural form.
Anyway, once you've 'Laravelized' your database, you can use an Eloquent model to setup awesome relationships with very minimal work. Here's what I think you'd want to do.
app/models/Team.php
class Team extends Eloquent {
// Yes, this can be empty. It just needs to be declared.
}
app/models/Fixture.php
class Fixture extends Eloquent {
public function homeTeam()
{
return $this->belongsTo('Team', 'home_team_id');
}
public function awayTeam()
{
return $this->belongsTo('Team', 'away_team_id');
}
}
Above, we created a simple model Team which Laravel will automatically look for in the teams database table.
Second, we created model Fixture which again, Laravel will use the fixtures table for. In this model, we specified two relationships. The belongsTo relationship takes two parameters, what model it is related to, in both cases here they are teams, and what the column name is.
Laravel will automatically take the value in away_team_id and search it against the id column in your teams table.
With just this minimal amount of code, you can then do things like this.
$fixture = Fixture::find(1); // Retrieves the fixture with and id of 1.
$awayTeam = $fixture->awayTeam()->first(); // var_dump this to see what you get.
$homeTeam = $fixutre->homeTeam()->first();
Then you can proceed as normal and access the column names for the tables. So say you have a 'name' column in the teams table. You can echo out the the home team name from the fixture like so.
$fixture = Fixture::find(1); // Get the fixture.
echo $fixture->homeTeam->name;
It's nearly 2AM, so there might be an error or two above, but it should work.
Make sure you check the docs for Eloquent, especially the bits relating to relationships. Remember to name your columns and tables in the way Laravel wants you to. If you don't, there are ways to specify your custom names.
If you want to get even more fancy, you can define the inverse relationship like this on your Team model.
app/models/Team.php
class Team extends Eloquent {
public function fixturesAtHome()
{
return $this->hasMany('Fixture', 'home_team_id');
}
public function fixturesAway()
{
return $this->hasMany('Fixture', 'away_team_id');
}
}
Then to get all of a particular team's home fixtures...
$team = Team::find(1); // Retreive team with id of 1;
$homeFixtures = $team->fixturesAtHome();
I have two domain classes in which one has a one to many relationship with the other
Class A
{
...
#NotNull
static hasMany = [bElements:B]
}
Class B
{
...
}
When I run the application, the relation table A_B is created and entries in A_B table are automatically added when user creates A objects. Then I've decided to change this relation, because I've noticed that it is better to have a relation between class A and class C, so class A now has
static hasMany = [cElements:C]
but when I create a new object of type A (after creation of some C objects), adding one or more objects of type C, in my database I don't see the entry into the A_C table, but only in A table.
Why do this beahavior happens? What must I control to resolve problem?
EDIT:
maybe it is needed some clarifications. The Class A is a class that describes an invoice and the class C is a class that describes the invoices items. So I need to give a one-to-many relationship between this two classes, but as described above, it does not work as expected...
EDIT 2:
I've noticed that maybe the problem depends on the fact that the field cElements in A object is null. In the view, I've described the cElements field as follows:
<g:select name="receiptItems" from="${HealthService.findAllByDoctor(Doctor.findBySecUser(new ReceiptController().getCurrentlyLoggedUser()))}"
multiple="multiple" optionKey="id"
optionValue="${{it.healthServiceType.healthService}}"
size="5" value="${receiptInstance?.healthServices*.id}" class="many-to-many"
onchange="${remoteFunction(
controller: 'Receipt',
action: 'sumReceiptItems',
params: '\'receiptItemsSelected=\' + jQuery(this).val()',
onSuccess: 'updateTotalAmount(\'totalAmount\', data, \'00000\')')}"/>
It is a multiple select. After each selection, with the remoteFunction, a method from controller is called to do some calculation and update the totalAmount field. It works well but, when save method is called, healthServices field is null...and I don't understand why...I will open another post to solve this issue (solved here)
If you declare a class like
Class A
{
...
#NotNull
static hasMany = [cElements:C]
}
Class C
{
static belongsTo= [a:A]
...
}
In this case it does not create A_C but if you declare it like
Class A
{
...
#NotNull
static hasMany = [cElements:C]
}
Class C
{
//no belongTo
...
}
then it creates A_C in database to map these fields id.
There is no need to have an intermediate table with A-B relations when you have one-to-many relation esablished. If relation was bidirectional (B class objects could have multiple A class objects) then the intermediate table would be useful.
Check your databse whether your B class objects contain pointers (foreign keys) to A class objects. If they do, your ORM decided to create one-to-many relationship and your A-B relations table is not used.
I would ditch the intermediate table for now and add the following to B class
static belongsTo = [parent:A]
(keep the hasMany in A):
This will create a bi-directional relationship from B to A (aka foreign key in B table). Make sure you are conscious of how cascading deletes are handled with belongsTo.
http://grails.org/doc/2.2.x/ref/Domain%20Classes/belongsTo.html
You mentioned pre-populating. Make sure you aren't violating any constraints. Bootstrap often fails silently. Add something like on your instance in question:
`
if (!b.save()) {
b.errors.each {
println it
}
}
`
After you get this relationship working, take a look at this talk if you need to refactor your relationship for gorm performance using an intermediary table. http://www.infoq.com/presentations/GORM-Performance