How to get relational data in Symfony? - orm

I have created two Entities.
1. Bookings
2. Restaurants
While generating booking inquiry, user will also select one restaurant from drop down list of all restaurants. So I have set Many2one relation in Bookings Entity.
class Bookings
{
...
/**
* #var int
*/
/**
* #ManyToOne(targetEntity="Restaurants", inversedBy="restaurant_id")
* #JoinColumn(name="restaurant_id", referencedColumnName="id", onDelete="CASCADE")
*/
private $restaurantId;
...
public function __construct() {
$this->restaurantId = new ArrayCollection();
}
...
}
So one restaurant is associated with each booking inquiry and multiple booking inquiries will be associated with every booking.
Now while fetching list of all booking inquiries from controller. I am getting only bookings table details. but how can I also get associated restaurant details like id and res_name along with every booking inquiry.
below is the query for fetching all booking inquiries.
$bookings = $this->getDoctrine()
->getRepository('AppBundle:Bookings')
->findAll();
but this query is returning only booking details not restaurant details, though I have set relationship in bookings entity. How can I get restaurant details along with every booking inquiry automatically in result set.

I can tell you straight away that your ManyToOne looks wrong:
/**
* #ManyToOne(targetEntity="Restaurants", inversedBy="restaurant_id")
* #JoinColumn(name="restaurant_id", referencedColumnName="id", onDelete="CASCADE")
*/
inversedby refers to the property which contains the OneToMany collection, which in your case would not be restaurant_id, it would be bookings.
So correctly:
/**
* #ManyToOne(targetEntity="Restaurants", inversedBy="bookings")
* #JoinColumn(name="restaurant_id", referencedColumnName="id", onDelete="CASCADE")
*/
protected $restaurant; // id not needed here, you're referencing a whole entity in doctrine not a single id
And Restaraunt entity should look something like:
/**
* Booking entity collection
*
* #OneToMany(targetEntity="Booking", mappedBy="restaurant")
*/
protected $bookings;
I recommend you read the association mapping documentation and make sure you have a thorough understanding how relations in doctrine work.

After doing Rnd for an hours, I discovered that the entities were not using PHP annotations, but rather the XML versions. So I added proper relations setting in xml file and its working now.

Related

Doctrine 3: one-to-one Unidirectional relationship doesn't return all fields

I have 2 Entities: Thesis and DoList.
Every DoList belongs to 0 or 1 Thesis. So we have a unidirectional one-to-one relationship from DoList to Thesis. Here is Thesis:
class Thesis
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
* #var int
*/
protected int $thesisID;
and DoList:
/**
* #ORM\OneToOne(targetEntity="Thesis")
* #ORM\JoinColumn(name="thesisID", referencedColumnName="thesisID", nullable=true)
*/
protected $thesisID;
Of course i cut down the classes to show only the part that matters.
As far as my understanding is going. #ORM\JoinColumn should join the tables DoList and Thesis on
DoList.thesisID and Thesis.thesisID.
I have no problem persisting thesisID in this relationship but i can't retrieve the value of thesisID when selecting all values from DoList it just always is null.
Edit:
The column names have to be thesisID on both sides.
The error was that i was not joining the tables when using the query builder.
I thought that when doing a query and selecting all rows from a table with query builder doctrine reads the relationship that i specified on the model and does the join query automatically.
NOTE: DOCTRINE DOES NOT AUTOMATICALLY JOIN TABLES WHEN YOU SPECIFY THAT OPTION ON YOUR MODEL. YOU NEED TO DO THE JOIN FUNCTIONALLITY ON QUERYBUILDER.
$qb->select(['u', 'c'])
->from('ThesisNET\Models\DoList', 'u')
->join('u.thesisID', 'c')
->where('u.instructor = ?1')
->setParameter('1', $username);
this is how it eventually worked. (i just added the join option.)

Join table groups on authentication in laravel 5.2

I am using laravel 5.2 to develop an application. Now what I need is I have two tables first one is users and second one is groups. Groups table is the parent table of the users table where groups_id is the column with foreign key with groups table (group_id). Now when login I am using the code as follows:
$users = User::leftJoin('groups', 'groups.group_id', '=', 'users.groups_id')->where('email', base64_decode(base64_decode(trim($request->input('user_login')))))->first();
where i used join to join the groups table. But It is executing perfectly but does not show the data in the session (Auth::user()).
So please suggest me how to add the second table in the session but only join the row with foreign key records.
Thanks.
You have define a relation in User Model like this
class User extends Authenticatable
{
......
/*
* Relation to Group Model
*
*/
public function group()
{
return $this->belongsTo('App\Models\Group','group_id','group_id');
}
......
}
Now you can access authored user group at anytime , anywhere by these line of code
auth()->user()->group()
or
$user = User::find($id);
$user->group();
and to retrieve users from a group you can define reverse of this relation in Group Model like this
class Group extends Mdoels
{
..........
public function Users()
{
return $this->hasMany('App\Models\Users','group_id','group_id');
}
..........
}
you can find more information on docs here

SQL subquery result in LINQ and Entity Framework Code First

I want to make a query that'll return me entities and additionally a number of one of their associated entities. For example:
select *, (select COUNT(*) from Forms where Contact_Id = Contacts.Id)
as FormsCount from Contacts;
My Contact entity has a property named FormsCount, but it isn't mapped since there's no column named like that in the table. Is it possible to write one LINQ query that'll return me Contact entities with the additional FormsCount property filled in?
Alternatively, I'd be happy if I could get the FormsCount values in a separate field and I can copy them to the entities manually. The result from the query could be in this form for example:
{
Contact Contact;
int FormsCount;
}
Then I can iterate over the results and copy FormsCount to Contact. Maybe this can be achieved by using projections?
I know how to do that using 2 queries:
a) fetch contact entities first
b) fetch pairs or contact ID and FormsCount for contacts returned in the first query.
But I'd like to do that using one query. Also, I don't want the FormsCount property to be always filled in my Contact entity, I want to have a control over that. Any ideas?
Thanks,
Michal
You are right about the projection.
If Contact has a navigation property Forms you can project:
from c in context.Contacts
select new { Contact = c, FormsCount = c.Forms.Count() }
If not, you'll have to use a subquery:
from c in context.Contacts
select new
{
Contact = c,
FormsCount = context.Forms.Count(f => f.Contact_Id == c.Id)
}
EF will handle both situations in one SQL query.

How to fetch out complex result from the database - Yii

i am facing problem to fetch out records from table using Yii relationship,
i have 3 tables
1) Students -> ID, Name, Roll_Number
2) Subjects -> ID, Name
3) Students_taken_Subjects -> ID, Student_ID, Subject_ID
Suppose there are number of students have taken more than one subjects which are stored in the 3rd table "Students_taken_Subjects" then how i can fetch out the list of students taken any specific subject?
e.g. list of students taken maths
which one from below relationships are correct and how can i get results into the $dataProvider variable?
'Students'=>array(self::HAS_MANY, 'Subjects', 'Student_ID'),
and
return array(
'Students'=>array(self::MANY_MANY, 'Subjects',
'Students_taken_Subjects(student_id, subject_id)'),
);
The relationship between Subjects and Students is MANY_MANY, but you've written it a bit wrong, This is what you need:
class Subjects extends CActiveRecord
{
// ...
public function relations()
{
return array(
'Students'=>array(self::MANY_MANY, 'Students', 'Students_taken_Subjects(Subject_ID, Student_ID)'),
);
}
// ...
}
Once you've written this relation, the Subjects active record will have a Students property that returns an array with the 0 or more students taking that subject. You can access them like this:
$subject = Subjects::model()->findByPk($pk);
$students = $subject->Students; // an array with the subject's students
The above code will result in two DB accesses, one for the $subject and one for the related $students. This might be fine, but if you are accessing a lot of subjects it could become a problem with too much "lazy loading". You can tell Yii to "eager load" the students along with the subjects like this:
$subjects = Subjects::model()->with('Students')->findAll();
Here you are finding all of the subjects, but alerting Yii--using with('Students')--that you'll be wanting each subject's student information as well. This ensures that all of the students related to the subjects you find will be grabbed at once. An alternative to the with() function is to use a criteria's with property:
$criteria=new CDbCriteria;
$criteria->with = array('Students');
$subjects = Subjects::model()->findAll($criteria);
Either way, when you do ask for a subject's students like this:
$subjects[0]->Students;
$subjects[1]->Students;
// ...
you will not get another DB call each time because Yii already loaded the data.
You'll need to provide more details about what you are wanting to do with the students in the data provider before I can give any more details about that.

NHibernate - how to get an item that is not referenced by an item in another table

Let's say I have a class Voucher:
public class Voucher
{
public Guid Id {get;set;}
public DateTime DateAvailable {get;set;}
}
and a class Entry
public class Entry
{
public Guid Id {get;set;}
public Voucher Voucher {get;set;}
// ... other unrelated properties
}
How can I create an NHibernate Criteria query that finds the first available voucher that is NOT currently assigned to an Entry?
The equivalent SQL would be
select
v.Id, v.DateAvailable
from
Voucher v
left join Entries e on e.VoucherId = v.Id
where
v.DateAvailable <= getutcdate() and
e.Id is null
Edit: I'm still unable to figure this one out. The Voucher table has no reference to the Entries table, but I need to find the first voucher (by date order) that has not been assigned to an entry. This seems like such a simple task, but everything I keep reading about using NHibernate criteria left joins requires the Voucher object to have a property that references the entry. Surely there's a way to invert the query or add a reference property to the Voucher object without modifying the database to have each table reference the other.
Edit 2: For what it's worth, I don't think it's possible to do what I was trying to do without some modifications. I eventually got a query to work using the Entry as the primary criteria with the Voucher as a sub-criteria, but then UniqueResult returned null, even if the data was there. I guess it just couldn't make the association.
In case anyone runs into this, I ended up making a foreign key in each table that references the other and using the References<> mapping to associate the two. It's not idea, because I have to manually set each entity's sub property to the other to make the association bidirectional, but it at least works without a ton of changes.
Translating your SQL literally:
var voucher = NHibernateSessionManager.Session.CreateCriteria<Voucher>("v")
.Add(Restrictions.Le("v.DateAvailable", DateTime.UtcNow))
.CreateCriteria("Entries", "e")
.Add(Restrictions.IsNull("e.Id"))
.SetMaxResults(1)
.UniqueResult<Voucher>();
Now if I understand this correctly there may be an alterantive.
If the statement: "..finds the first available voucher that is NOT currently assigned to an Entry..." is the same with the statment "finds the first available voucher that has no entries..." (since the voucher is the entity that has many entries... according to your classes) then you could do:
var voucher = NHibernateSessionManager.Session.CreateCriteria<Voucher>()
.Add(Restrictions.IsEmpty("Entries"))
.Add(Restrictions.Le("DateAvailable", DateTime.UtcNow))
.SetMaxResults(1)
.UniqueResult<Voucher>();
...assuming that you have mapped the Entries property in the Voucher entity.
But maybe I got it wrong...
The following should work using HQL:
IQuery query = session.CreateQuery(#"
FROM
Voucher v LEFT JOIN
Entry e
WHERE
e.ID IS NULL AND
v.DateAvailable <= :now
");
query.SetParameter("now", DateTime.Now);
// If you want to restrict to only the first result
query.SetMaxResults(1);
Voucher v = query.UniqueResult<Voucher>();
// Otherwise, get a list of results...
// List<Entry> results = query.List<Entry>();
From memory, might not work:
session.CreateQuery<Entry>().CreateAlias("Voucher","v").Add(Restrictions.And(
Restrictions.Lt("DateAvailable",DateTime.Now),
Restrictions.Eq("v.Id",null")
).List<Voucher>();