database modeling: null foreign keys by entity type - database

I need some help designing my database relationships.
I have these tables: documents, companies, individuals and users. A document can be internal or external.
If it is external, it can be signed by a company or an individual.
If it is internal it has to be signed by a user.
In any case, the document is signed by a single entity (company, individual or user). I was thinking of creating the documents table in the following way:
documents
----------
id_document
...
type
id_user
id_company
id_indiv
where type can be 0: internal, 1: external and id_user, id_company, id_indiv are foreign keys of the respective tables and can be null. Is this logic okay? Can someone suggest me a better idea?

Laravel's Eloquent ORM provides the Polymorphic relationship to handle this kind of problem.
To be more specific, you can place two fields; documentable_type and documentable_id inside your document table. And then add these relationship methods to each model;
class Document extends Model
{
/**
* Get the owning imageable model.
*/
public function signer()
{
return $this->morphTo();
}
}
class User extends Model
{
/**
* Get the documents signed by this user.
*/
public function documents()
{
return $this->morphMany('App\Models\Document', 'documentable');
}
}
class Company extends Model
{
/**
* Get the documents signed by this company.
*/
public function documents()
{
return $this->morphMany('App\Models\Document', 'documentable');
}
}
class Individual extends Model
{
/**
* Get the documents signed by this individual.
*/
public function documents()
{
return $this->morphMany('App\Models\Document', 'documentable');
}
}
Then you can use the following snippets;
$document->signer; // This returns either user or company or individual
$company->documents; // This returns a collection of document models which is signed by this company
$individual->documents;
$user->documents;
For more details, see this link; https://laravel.com/docs/8.x/eloquent-relationships#polymorphic-relationships

Related

get product name with category name and subcategories name in laravel

I need category name with product name, I have two tables in databse categories and prodcuts, i want to get products regarding or with referance of related category
Example:-
Category and subcatagory with list
You need to build a many-to-many relationship, because each product can have multiple categories and each category can be associated to multiple products.
Laravel documentation is pretty good, you can check it out: https://laravel.com/docs/5.5/eloquent-relationships#many-to-many
Assuming your models are Product and Category, you can do as follows:
Inside your Product.php class:
public function categories() {
return $this->belongsToMany('App\Category');
}
Inside your Category.php class:
public function products() {
return $this->belongsToMany('App\Product');
}
Now you need to create the table in the DB to support the relationship (in a many-yo-many relationship, this table is called pivot)
Create a new migration similar to the following:
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('category_product', function (Blueprint $table) {
$table->integer('category_id')->unsigned()->index();
$table->foreign('category_id')->references('id')->on('categories');
$table->integer('product_id')->unsigned()->index();
$table->foreign('product_id')->references('id')->on('products');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('category_product');
}
Now you can get the categories of a product very simply:
$product->categories; // You get a collection of categories
$product->categories(); // You get the query if you need to add some filters
In a similar way, you get all the products of a specific category with:
$category->products;
To add a category to your product, you can do in many ways, some are:
$product->categories()->attach($category_id);
$product->categories()->sync([$category_id1, $category_id2, ..]);
For more details of specific needs, you can read through the documentation i linked above

Eloquent relation with where condition on model attribute

I have two models Student and StudentRevision with Student model having hasMany relation with StudentRevision model. I have defined a hasMany relation in Student as
public function revisions()
{
return $this->hasMany(
'StudentRevision',
'sid'
);
}
I have a field in students table (Student model) which references current revision of student from student_revisions table.
The table structure is something like this.
students sid srid name ....
student_revisions srid sid batch ....
Now i want to define hasOne relation with StudentRevision model which references current revision linked with Student. Currently I have defined this relation as:
public function current()
{
return $this->hasOne(
'StudentRevision',
'sid'
)
->where('srid', $this->srid);
}
But the problem with this relation is, that $this->srid is not available during query building process and can be only there after the actual model is available.
Please help how to overcome this.
I don't think you can define it as relation. But what you can do is this:
public function current(){
return $this->revisions()->where('srid', $this->srid)->get();
}
This way you can access it by $student->current(). You can even go a bit further and make it more relationship like:
public function current(){
return $this->revisions()->where('srid', $this->srid);
}
public function getCurrent(){
return $this->current()->get();
}
protected $appends = array('current');
Here we define an accessor for our attribute. Laravel Docs (scroll down to the bottom)
We can then use it like this:
$student->current; // retrieves the model
$student->current(); // retrieves an instance of the query builder

How to persist Entity object which contains another Entity Objects to the database?

I have a problem with my function which is supposed to save data to database, function creates a new object which includes other objects. I am able to save and fetch objects which contain only primitive data types and Strings to Database , so the database and system works in this case. I am using JavaEE and EntityManager (persist).
Any help?
You can define a cascade type on the parent entity. Have a look on the Java EE tutorial (http://docs.oracle.com/javaee/6/tutorial/doc/bnbqa.html#bnbqm)
see the principal below
#Entity
public class Customer {
#OneToMany(cascade=CascadeType.ALL, mappedBy="customer")
public Set<Order> getOrders() {
return orders;
}
...
}
#Entity
public class Order {
#OneToOne
Customer customer;
...
}

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
}
}

Cannot associate an entity obtained from a transaction to another entity in Objectify

I have some issues with Entity relationships in Objectify. My application is an event application where events have tickets of different categories; each ticket is owned by a user. I have a parent/child hierarchy like so Event > TicketType > Ticket. So, Event is #Parent of TicketType which is #Parent of Ticket.
Here are my entities:
#Entity
public class Event {
...
#Load
private Set<Ref<TicketType>> ticketTypes = new HashSet<Ref<TicketType>>();
...
}
#Entity
public class TicketType {
...
#Parent
private Ref<Event> event;
...
}
#Entity
public class Ticket {
...
#Parent
#Load
private Ref<TicketType> ticketType;
...
}
I create the Event inside a transaction like so:
Event ev = ofy().transact(new Work<Event>() {
#Override
public Event run() {
// several statements constructing the event
ev.setXXXX(X);
ofy().save().entity(ev).now();
// Now construct the TicketType entity, then associate it to its parent, Event
TicketType tt1 = new TicketType("normal", 100, 7);
tt1.setEvent(ev);
ofy().save().entity(tt1).now();
return ev;
}
});
Using the returned ev, I create the tickets like so:
// Generate a VIP ticket
Ticket ticket1 = ev.generateTicket("vip");
// I set the owner with an already saved User entity
ticket1.setOwner(cl);
ofy().save().entity(ticket1).now();
// The user also has a list of all his tickets
cl.addTicket(ticket1);
Inside Event.generateTicket(...), I do:
public synchronized Ticket generateTicket(String type) throws IllegalArgumentException {
for (Ref<TicketType> reftt : ticketTypes) {
TicketType tt = reftt.get();
if (tt.getType().equalsIgnoreCase(type)) {
if (tt.getAvailable() > 0) {
Ticket newTicket = new Ticket(RandomGenerator.nextNumber(TICKET_NUMBER_LENGTH), tt);
newTicket.setExpirationDate(getEndDate());
// here I set the parent TicketType entity for this new Ticket
newTicket.setTicketType(tt);
// the number of available tickets of this type is decreased
tt.setAvailable(tt.getAvailable() - 1);
return newTicket;
} else return null;
}
}
throw new IllegalArgumentException("No such type");
}
My problem is that the parent/child relationship seems to be respected only on the Event entity that properly has a list of all Event/TicketTypes (through the ticketTypes field, which is a Set<Ref<TicketType>>. But, the TicketType entity does not have the list of tickets (the tickets field is null, so not saved), and in the other direction, the TicketType parent reference in Ticket is null, so is the Event parent reference in TicketType, despite the assignments I did in both cases above.
What do I do wrong?
I don't think you're doing anything wrong here. I do however believe that Objectify will not automatically load one-to-many relationships. The proper way to get all your ticket types would be to first load the Event entity and then perform an ancestor query for the ticket type.
Some advice:
It looks like you are designing your entities like you would design tables in a relational database. Such concepts do not apply to datastore. As stated in the objectify introduction you should imagine the datastore as a hashmap of a hashmap. It might me feasible to use a multivalue attribute which contains enum values for the ticket type in your ticket entity. Less entities is always a good thing in datastore.

Resources