Grails Relation m:n:n - database

We work with an existing mysql database under grails which contains a m:n relation. No problem here. But now we are in the situation that i have to add a second n relation entry, which links to the same table and has to be associated to the first n entry.
If it were for the database, I would simply create a table which looks like:
field m_id -> links to m table
field n_id1 -> links to n table
field n_id2 -> links to n table
But how can this be represented in a grails domain class?
Possibly the answer can already be found somewhere, but the searches I did were not successful, maybe due to lack of search term creativity.
EDIT:
Trying to clarify the question: we have a many-to-many relation, but with two items on one side, which have to maintain association to each other (and it also must be clear which is for example the original and which is the replacement item), so they can not be seperated into two separate entries into the relation.
Hmm... try to think of racing car drivers nominating for a series of races, and every nomination has to contain the driver and his substitute. Races would be m (left hand), driver would be n1 and substitute would be n2. (It was really hard work to find an example...)
EDIT:
By coincidence I found this question which addresses the same problem but also left off rather unsolved.

Take a look at the documentation, is pretty clear:
http://grails.github.io/grails-doc/2.5.0/guide/GORM.html#gormAssociation
Anyway I'm not sure I understand what you're trying to do, but let's try.
If it's a one-to-one relation, you could simply do something like this:
class DomainA {
DomainB domainB
DomainC firstDomainC
DomainC secondDomainC
}
class DomainB {
}
class DomainC {
}
That would create the following fields in the "domain_a" table:
"domain_b_id"
"first_domain_c_id"
"second_domain_c_id"
If it's a one-to-many relationship from DomainA to both DomainB and DomainC with two differentiated collections of DomainC in DomainA, you must have two different DomainA properties in DomainC to be able to map it.
The example with Airport and Flight in the documentation:
class Airport {
static hasMany = [outboundFlights: Flight, inboundFlights: Flight]
static mappedBy = [outboundFlights: "departureAirport",
inboundFlights: "destinationAirport"]
}
class Flight {
Airport departureAirport
Airport destinationAirport
}
The flight needs to Airport properties in order to be able to distinguish which one is mapping the right hasMany collection in Airport.
EDIT: for the race-driver example
Grails supports many-to-many relations but one of the ends must be the principal one and the other must additionally have a belongsTo to it. Though this is not the case, since neither race belongs to driver nor driver belongs to race.
I would use relation with a property: "drives" with a property "mainDriver".
That cannot be mapped directly, you need to use a domain for the relation:
class Race {
static hasMany = [ participants: DriverRace ]
def mainDrivers() {
getDrivers( false )
}
def substitutes() {
getDrivers( false )
}
private getDrivers( mainDriver ) {
DriverRace.withCriteria {
eq( "race", this )
eq( "mainDriver", mainDriver )
}.collect { it.driver }
}
}
class Driver {
static hasMany = [ races: DriverRace ]
}
class DriverRace {
static belongsTo = [ race: Race, driver: Driver ]
boolean mainDriver
}

We thought we were able to solve the problem by inserting a second reference to domain/table n in the mapping property of (left hand side) domain m. grails then seems to put a second reference to n on the right hand side of the relation. But that turned out to be a hopeful weekend dream.

Related

Laravel multiple user id tables

I'm pretty new to laravel and have a really basic question related to relationships.
Here is an example of my question:
I have a migration called money_transfers.
The migration contains the following things:
user_id (transfer sent by)
sentTo_id (transfer sent to)
amount
sent_at
BOTH user_id and sentTo_id refer to a User ID.
Now, what I want to do is the following:
Fetch the user the money was sent TO the same way as the user the money was sent BY. Just like in the example below:
$transfer->sentTo->name
or
$transfer->sentTo->id
You get what I mean. Thanks in advance :)
If you defined your foreign keys correctly in your migration table, Then it's just a matter of defining the right relationship:
class MoneyTransfer extends Model
{
public function sentBy()
{
return $this->belongsTo(User::class,'user_id');
}
public function sentTo()
{
return $this->belongsTo(User::class,'sentTo_id');
}
}
This way you can access the receiver attribute like this:
$transfer->sentTo->name;
And the sender attribute like this:
$transfer->sentBy->name;

Use two completely different classes as one

I have very stupid question about design patterns: let's say we have two classes Post and Product, for each of them we have different table in the DB, and they have nothing in common with each other, so we can't create base class for them. Some Posts even contains Products. And here's what we should do with them:
Somehow store Post and Product instances in the DB, pack them in one array(using C++, if it matters) when user requests news feed from the next item, send it to the client, and receive and unpack on the client side(using Java).
Next, we have to show both Post and Product in the one list(such as news feed on the Facebook).
Also, we can share Post or Product with our friends using chat. So we can send Post or Product as an attachment of the message(consequently, we should to store id of sent Post or Product in the column attached_item of the messages table in the DB on the server side).
So, what design pattern would be best here? How should I implement the Post and Product classes?
It is a very broad question, but here is a skeleton of what you could you, just to give you some ideas:
// An interface containing methods specific to objects you can list
interface Listable {}
// An interface containing methods specific to objects you can share
interface Shareable {}
// An interface containing methods specific to objects you can send
interface Sendable {}
class Post implements Listable, Shareable, Sendable {
List<Product> products;
}
class Product implements Listable, Shareable, Sendable {
}
class ListManager {
public void addToList(Listable element) { }
}
class ShareManager {
public void share(Shareable element) { }
}
class SendManager {
public void send(Sendable element) { }
}
You could then use Post and Product interchangeably this way:
Post post = new Post();
Product product = new Product();
ListManager listManager = new ListManager();
listManager.addToList(post);
listManager.addToList(product);
ShareManager shareManager = new ShareManager();
shareManager.share(post);
shareManager.share(product);
SendManager sendManager = new SendManager();
sendManager.send(post);
sendManager.send(product);
Regarding the database representation, as suggested fusiled in his comment, just stick them in 2 separate tables. With a mapping table in between to link the products to their post.
EDIT
Regarding the issue with the MESSAGES table
You could add a new mapping table MESSAGE_ATTACHED_ITEM with columns messageId, postId, productId. Only set a value to the relevant colum when attaching an item to a message
Or an other option would be to have an ATTACHED_ITEM table with an id only.
And have Post and Product tables to have a foreign key to this table Id.
you can then stick this attachedItemId into your attached_item column
I think the solution could be simpler than you think. Why don't you ust use a common Java-like interface and hide the implementation details?
Just implement a common interface with the methods you need. Supposing this common interface is called EntityInterface:
public class Post implements EntityInterface {};
public class Product implements EntityInterface {};
Then when you want to handle these classes, you treat them as an EntityInterface object:
EntityInterface myNewPost = new Post();
EntityInterface myNewProduct = new Product();
//Now you see myNewProduct and myNewPost as EntityInterface objects
These code fragments are in Java, but use virtual functions in C++ and you get the same.

Using Eloquent for this kind of relationship

This is what my table relationship is like:
One user may have multiple groups. One group may have multiple users.
One message maybe be only by one user and group.
I have three models in laravel.
User,Message, and Group. And my pivot table is mssg_group which stores which user sent which message to which group.
(if this design is incorrect, do tell me the better way).
How do I write relationships to access all messages before a certain time by supplying a groupID?
I think your searching for the hasManyThrough relationship.
You need a Group model with a relationship to messages. See the Laravel Docs for more info.
/**
* app/Group.php
*/
public function messages(){
return $this->hasManyThrough('App\Message','App\MessageGroup');
}
In your Message Group Model you need to create the messages relation.
/*
* app/MessageGroup.php
*/
protected $table = "mssg_grp";
public function messages(){
return $this->hasMany('App\Message','id','mssg_id');
}
In your Message model be sure to define your custom table name.
/*
* app/Message.php
*/
class Message extends Model {
protected $table = 'mssg';
}
In your controller you can eager load the date requirement.
$group_messages = Group::where('id', $group_id)->with(function($query)
{
return $query->where('created_at','>',$date);
})->get()
I haven't tested it, so this may need to be tweaked a little bit, but it should get you close to where you want to be. I haven't address retrieving users, but it should be nearly the same as getting the messages synced up. Let me know if this helps.

Database One-to-Many with two foreign key fields in Laravel

I have been trying to define some Database schema to use the laravel framework. I want to model a Football match. The first step I wanted to do is to define the Entity Relationship diagram, but I found this (which I thought would be quite trivial) to be confusing in some aspects.
First, the obvious approach is to say that a Match is related with two Teams, and a Team is related to any number of Matches. So, we would have a "Many to Many" relationship.
But the implementation of a many to many relation is to have two tables and an intermediate table to relate both entities. I think this would be too much, when I know that a Match will always have two Teams and simply having two columns (local_id and visitant_id) with foreign keys to the Teams table would be enough. Plus, I want to be able to do:
Match::find(1)->local() or Match::find(1)->visitant();
So, thinking on this I am implementing a "One to Many" relation, but with this I have another issue. To retrieve all the matches a Team has played I would like to do:
Team::find(1)->matches();
But I cannot do this because I can only specify one key column when defining the matches() method in eloquent (by default it would be team_id, but it should be visitant_id and local_id).
After some more digging into the source code I found there is a way to actually keep my database schema as it is and achieve what I want (at least in Laravel 4). I posted my problem in github and Taylor Otwell (creator of the framework) gave me the correct answer: https://github.com/laravel/framework/issues/1272
Quoting him, it should be as easy as this:
class Team extends Eloquent {
public function allMatches()
{
return $this->hasMany('Match', 'visitant_id')->orWhere('local_id', $this->id);
}
}
And then...
$team = Team::find(2);
$matches = $team->allMatches;
This is one of those famous database design problems. Friendship relationships, for instance, suffer from that same difficulty. Since you are using Eloquent, I would suggest you to stick with many to many approach and have an extra boolean column local on your intermediate table
class Match extends Eloquent {
public $includes = array('team'); // Always eager load teams
public function teams() {
return $this->has_many_and_belongs_to('team')->with('local');
}
public function get_local() {
foreach ($this->teams as $team) {
if ($team->pivot->local) return $team;
}
}
public function get_visitant() {
foreach ($this->teams as $team) {
if (!$team->pivot->local) return $team;
}
}
}
class Team extends Eloquent {
public function matches() {
return $this->has_many_and_belongs_to('match')->with('local');
}
// I'm doing separate queries here because a team may have
// hundreds of matches and it's not worth looping through
// all of them to retrieve the local ones
public function matches_as_local() {
return $this->has_many_and_belongs_to('match')->with('local')
->where('pivot_local', '=', 1);
}
public function matches_as_visitant() {
return $this->has_many_and_belongs_to('match')->with('local')
->where('pivot_local', '=', 0);
}
}
Obs:
The method has_many_and_belongs_to(...)->with('field') has nothing to do with eager loading. It tells Eloquent to load the intermediate table column field and put that in the pivot.
Usage:
$match = Match::find(1);
$match->local; // returns local team
$match->visitant; // returns visitant team
$team = Team::find(1);
$team->matches; // returns all matches
$team->matches_as_local; // ...
$team->matches_as_visitant; // ...
foreach ($team->matches as $match) {
if ($match->pivot->local) {
// put nice local icon here
} else {
// put nice visitant icon here
}
}

Grails one to one relation

I tried to define one to one relation in 2 different way:
Grails 2.0.3
Case 1:
class Car {
String model
Engine eng
static constraints = {
eng unique: true
}
}
class Engine {
Double capacity
static belongsTo = [car : Car]
}
Case 2:
class Car {
String model
static hasOne = [eng : Engine]
static constraints = {
eng unique: true
}
}
class Engine {
Double capacity
static belongsTo = [car : Car]
}
looks similar, and both provide one to one bidirectional mapping. Unfortunately DB has different structure in both cases.
Case 1:
Case 2:
Why once Car and once Engine keeps link to second table.
Where is my problem? When I am looking at the code, from DDD perspective, both cases suggest that Car class is more important and Car aggregates Engine. Unfortunately when I look from DB side on case 2 I would rather said that it is opposite - Engine aggregate Car. Of course I can use first approach, but most of publication I saw about grails, present second way for defining relation. Maybe I misunderstood something and I use hasOne in wrong way?
The documentation on hasOne states that using this creates a bi-directional one-to-one relationship where the foreign key is on the child.
The belongsTo means that actions performed on the parent (eg save and update) will be cascaded by hibernate to the child.
So if you want the foreign key to be on Engine use static hasOne = [engine:Engine] on Car.
If you want the foreign key to be on Car then use Engine engine on Car .
In both cases use belongsTo = [car: Car] on Engine
I think you should try to make this aproach.
class Car {
String model
Engine engine
static constraints = {
eng unique: true
}
}
class Engine {
Double capacity
Car car
}
I think that will make it. You can read it here:
By default the address association would map to a foreign key column
called address_id.
http://grails.org/doc/latest/guide/GORM.html
on the Many-to-One/One-to-One Mappings
Hope it helps :)

Resources