I have three entities: User, Answer, and Question.
There is a OneToMany relationship between User and Answer and a ManyToOne relationship between Answer and Question. Basically, a particular user optionally gives answers to a bunch of questions.
What I'm trying to accomplish in the world of ORM is retrieving ALL questions and their associated answers for a particular user. The key part is that a user may not have answered a particular question but I still want to get that question (with a null answer).
My Answer entity has a 'user' field which maps to the User entity which is inverted by an 'answers' field within the User entity. If I use this 'answers' field within the User entity, I only get the question/answer pairs for which the user has actually answered. I do not get questions for which the user has not answered.
Typically, using raw SQL, this would involve a simple "left outer join" between my question and answer table, but I want this to be done using Doctrine's ORM. Any suggestions? I'm pretty new to the world of ORM.
I did it! Here's how:
I created a field in my Question entity that contains all answers, from all users, for that particular question; its mapped with a OneToMany relationship to the Answer entity. And then to make sure we restrict that list to the answers for a particular user I created a custom repository for my Question entity and created the following function:
public function findAllJoinedToAnswer($user)
{
$query = $this->getEntityManager()
->createQuery('
SELECT q, a
FROM Bundle:Question q
LEFT JOIN q.answers a
WITH a.user = :user'
)->setParameter('user', $user);
try{
return $query->getResult();
}catch (\Doctrine\ORM\NoResultException $e) {
return null;
}
}
Just pass in an instance of the User entity, and voila!
Related
I'm trying to figure out what is the best practice with selecting data from two related model.
I have a model (and a db table) "person" and then i have a model (and a db table) comment. There may be multiple comments for one person and comment has "person_id" column.
I have two cases in particular.
First i need to show persons profile with all his comments.
In my controller do I select the needed person through my person model and then select all the comments through my comments model? Or is it more correct for person model already return person with all comments?
I myself would guess that first option is ok.
Second case is where i need to show all latest comments with name of the person who made the comment.
So in my controller is it correct to select all latest comments from comments model and then select a person for each or them? Or is it more correct for the comments model to return comment with person name included?
In this case i would guess that second option is better. It seems really strange to first select comments and then iterate them and select a person for each of them.
So im kind of confused because case 1 and 2 seem similar but i would use different solutions for them. Which one is correct?
This question already has answers here:
Doctrine2: Best way to handle many-to-many with extra columns in reference table
(13 answers)
Closed 7 years ago.
I have "customers", "products" and "versions" tables.Each customer, can have more than one product, and each product has more than one version. I have created many-to-many relation "customers_products" and everything works perfect.
Also I have created one-to-many relation between "products" and "versions".
QUESTION:
How to add an extra column (version_id) in "customers_products" table so I can build form where user can choose products and version to create new customer.
Once an association has data, it's no more an association.
You have to implement two ManyToOne instead of a ManyToMany.
See this great answer on this question for a full example.
You can get a lot of other examples by googling the title of your question.
Adding an extra column to the association of a many-to-many it actually changes the meaning of that relationship. In order to represent that with Doctrine, you'd need to change the association to be a one-to-many/many-to-one between the three entities.
You'll end up with three entities in your domain model, which would allow you to access to the version of a CustomerProduct entity.
You can read a bit more detailed explanation in Doctrine's docs.
I have three tables: groups, questions and answers.
groups is connected to questions in a one to many relationship. Similarly, questions has a one to many relationship with answers. Editors provide an answer to a given question after an admin submits the groups and questions.
How do I create this in Laravel 5? I think to creating a pivot table for group_question and question_answer is the right place to start, but I am not sure because I don't know how to later select questions and answers together. Should I instead use json and save all questions and answers to one record?
There are a number of ways to tackle your problem in Laravel, but the easiest way is probably by using the hasManyThrough relationship. Which can be defined in your Group class something like this:
class Group extends Model {
public function answers(){
return $this->hasManyThrough('App\Answer','App\Question');
}
}
just be sure your tables have the following foreign key fields
groups
id - integer
name - string
questions
id - integer
group_id - integer
text - string
answers
id - integer
question_id - integer
text - string
you can read up on more on this in the laravel docs under eloquent relationships.
See more from Laravel 5's docs on the hasManyThrough relationship here.
I have a Question model which has a one to many relationship with an Answer model.
Now I want to add upvote/downvote funcionality to both of these models, do I need to create two tables like VotesQuestions and VotesAnswers or can I somehow manage with one? If so, how?
You can use a polymorphic relationship. This is built into Laravel. Documentation is here. The code shown here is for Laravel 4, but the functionality is the same for Laravel 5.
Create a votes table, and make sure it has at least two specific fields: votable_id and votable_type. In a database migration, you would use the statement $table->morphs('votable');, and it will create the two fields. You can have as many other fields as you like, but to make sure the relationship works, those two fields are required.
Next, setup the Vote model with the votable relationship. The name of this relationship should match the base name of the fields you created:
class Vote extends Eloquent {
public function votable() {
return $this->morphTo();
}
}
With this setup, you can now associate votes to any model you want. Go ahead and add the votes relationship to the Question and Answer models:
class Question extends Eloquent {
public function votes() {
return $this->morphMany('Vote', 'votable');
}
}
class Answer extends Eloquent {
public function votes() {
return $this->morphMany('Vote', 'votable');
}
}
You can now access the votes for any question/answer through the relationship:
$q = Question::first();
$qVotes = $q->votes; // Collection of votes for the question.
$a = Answer::first();
$aVotes = $a->votes; // Collection of votes for the answer.
You can also get the related question/answer model through the vote, if you ever need to:
$v = Vote::first();
$vRelated = $v->votable; // Will automatically be a Question or Answer object, depending on what the vote was for.
I would do an table for the question and when you want to up/downvote the question there should be a count column for both, otherwise you want to log it that an user can only vote for it once, so you need another table for user_id, question_id and type (up/down).
ofc you can handle it with one table, but that is really worth because you save many things that are not necessary.
you can create a table with an internal id, 1,2,3,4 and 1 is always the question or 0 and 2-xx (1-xxx) are always the answers. so you can handle it with one table
You could create a generic Votes model/table which has a field called "model" and "model_id" and then use reflection to get the correct object.
I have a lot of times 2 or more entities who are related to.
For example:
entity avance(): with attributes: id, userId, questionnaireId, questionId
entity questionnaire: id, name, questionsNbres
entity questions: id, question, responseA, responseB, responseC, correctResponse
When I call an avance entity, it is complicated to find the questionnaire name attribut, I have to do a lot of foreach to find the correct one. The same for all the questions that are related to.
I'm sure that a best solution exist, for example with a inner join, but I don't know how to do this in symfony.
You get two tools that responds to theses problems.
You can setup annotations in yours models to automate data fetching. This is the JoinColumn annotation
However, because the JoinColumn usually over-fetching, my recommandation would be to put in place a custom repository, it allow to create complex query with joins.
In your case, I think you need a left join aka "extends my datas, with another data set".