I am having problem with Laravel Eloquent relations i understand how they work but i dont know how to "use" them properly, so i need some guidance/pointers.So here goes.
I have Exam table
Schema looks like (thanks to lukasgeiter)
exams
id
title
duration
questions
id
text
exam_id
answers
id
text
question_id
correct (boolean)
Relations:
Exam Model
public function questions(){
return $this->hasMany('Question');
}
Question Model
public function answers(){
return $this->hasMany('Answer');
}
public function exam(){
return $this->belongsTo('Exam');
}
Answer Model
public function question(){
return $this->belongsTo('Question');
}
And i understand this part but now i want users to be able to solve exam and store that data (i need to save an answer from user, for example user_id 1, exam_id 2, question_id 1, answer true). i have done it this way but i think its wrong (Yeah it does work but i dont think its the right way)
Schema looks like
Users
id
email
pass
...
SolvedExams
id
user_id
exam_id (havent put relation here not sure if needed)
solved (boolean) // if its completed right or wrong
SolvedQuestions
id
exam_id (havent put relation here not sure if needed)
answer(boolean)(then later i check this boolean with answers) //if the answer is right or wrong
Now with relations i have done same as i said before
User Model
public function SolvedExams() {
return $this->hasMany('SolvedExams');
}
SolvedExam model
public function User() {
return $this->belongsToMany('User');
}
public function questions() {
return $this->hasMany('solved');
}
SolvedQuestions model
public function exam() {
return $this->belongsTo('SolvedExam');
}
Is this the right way or am i doing it wrong (and I am a begginer with relations)
I think you are pretty close...
I'd do it this way:
Tables
exams
id, title, duration
questions
id, text, exam_id
answers
id, text, question_id, correct
users
id, email, password
tries
id, user_id, exam_id
answers_try (pivot table)
id, try_id, answer_id
Relations
Exam
public function questions(){
return $this->hasMany('Question');
}
public function tries(){
return $this->hasMany('Try');
}
Question
public function answers(){
return $this->hasMany('Answer');
}
public function exam(){
return $this->hasMany('Exam');
}
Answer
public function question(){
return $this->belongsTo('Question');
}
public function tries(){
return $this->belongsToMany('Try');
}
User
public function tries(){
return $this->hasMany('Try');
}
Try
public function answers(){
return $this->belongsToMany('Answer');
}
public function user(){
return $this->belongsTo('User');
}
public function exam(){
return $this->belongsTo('Exam');
}
Usage
Get the users answer for a question
$answer = User::find(1)
->tries()->where('exam_id', 2)->first()
->answers()->where('question_id', 3)->first();
Creating a new exam
$exam = new Exam;
$exam->save();
$question = new Question;
$question->text = 'Foo?';
$exam->questions()->save($question);
$answer1 = new Answer;
$answer1->text = 'Foo!';
$answer1->correct = true;
$answer2 = new Answer;
$answer2->text = 'Bar!';
$answer2->correct = false;
$question->answers()->saveMany([$answer1, $answer2]);
Saving users answer
$exam = Exam::find(1);
$user = Auth::user();
$try = new Try;
$try->user()->associate($user)->save();
$exam->tries()->save($try);
$try->answers()->attach(2); // 2 is the answer id
Related
As I mentioned in Question, the current Laravel 6.0 project I am working on has bit weird DB setup, where the Model's(the MainModel here) MySQL table has been set with AutoIncrement as NULL. And client won't allow to change the Table's definition at all.
I want to reliably find the next and previous IDs of the Model(since I can't find from table as AutoIncrement is set to NULL) before inserting record, so that I can make an entry of relevant record(for eg. image(s) of a testimonial/faq or any WYSIWYG content field) into another referential table first, by correctly inserting the main Model's ID into the refrential ID field of that another table.
Currently I have this in my main Model, but the next method doesn't reliably return the exact incremented ID consistently:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Te7aHoudini\LaravelTrix\Traits\HasTrixRichText;
class [MainModel] extends Model
{
use HasTrixRichText;
protected $guarded = [];
public $timestamps = false;
protected $primaryKey = 'id';
protected $connection = '[connection1]';
protected $table = '[main_table]';
protected $fillable = ['id', '[titlefield]', '[wysiwyg_field]'];
/**
* Setup model event hooks
*/
public static function boot()
{
parent::boot();
self::creating(function ($model) {
$model->id = $model->max('id') + 1;
});
}
/**
* Get next available Faq Id
*/
public function next()
{
return ++$this->id;
}
}
Any help is appreciated...
As I understand you are confused about how to call statically model queries. You can achieve the same logic by using a static self-reference static.
public static function next()
{
return static::max('id') + 1;
}
This would be equivalent to.
MainModel::max('id');
Bonus to make it a transaction to avoid id clashing. This can lock the database in fun ways, but will avoid you have the same ids, something similar to this, very simple example.
DB::transaction(function () {
$id= MainModel::next();
$newModel = MainModel::create(['id' => $id]);
});
As I understanding, in order to get the next increment id, you need to call the following line.
Model::lastest()->first()
I want to ask about how to retrieve all data in laravel
I have tables like this
Corp
corp_id
corp_name
Subsidiary
subsidiary_id
corp_id
subsidiary_name
Customer PIC
cust_pic_id
corp_id
subsidiary_id
cust_name
cust_phone
cust_address
cust_email
Each model like this
corp model
protected $table= 'corps';
public function CustomerPIC()
{
return $this->hasMany('App\CustomerPIC');
}
subsidiary model
protected $table = 'subsidiaries';
public function CustomerPIC()
{
return $this->hasMany('App\CustomerPIC');
}
customer PIC model
protected $table = 'customer_P_I_CS';
public function corp()
{
return $this->belongsTo('App\Corp');
}
public function subsidiary()
{
return $this->belongsTo('App\Subsidiary');
}
and I have a controller
public function getCustomer()
{
$getData = CustomerPIC::with(['Corp','Subsidiary'])->get();
return response()->json([
'data'=>$getData
]);
}
The question is, why I get the return without corp_name and subsidiary_name. and there is corp:NULL and subsidiary: NULL even I don't have that row
Which is there is no corp_name and subsidiary_name?
I want to return all of data.
Thank you for read it
Make sure you load relationships with lowercase (same as you defined relationships):
$getData = CustomerPIC::with(['corp','subsidiary'])->get();
I recently started experimenting with Raw SQL using Entity Framework, and I prefer it in some cases.
I would like to know if there is a way to grab relational entities:
Dosnt work:
var personNo = context.Person.SqlQuery("SELECT * FROM `Person` LIMIT 1").FirstOrDefault();
foreach(var Number in personNo.Phone) {
//never iterates
}
Works (but LINQ-to-Entities which I dont want in this case):
var personNo = context.Person.FirstOrDefault();
foreach(var Number in personNo.Phone) {
//iterate twice as it contains in the db
}
I tried a couple of different queries including
SELECT * FROM `Person` LEFT JOIN `Phone` ON (`Person`.ID = `Phone`.PersonID) LIMIT 1
What is the correct way to write the query on to recieve the list of Phone numbers? Is this possible?
You can do SQL to entities. I prefer this way when I have joins and group bys in them, and don't have permission to create a view.
First, create a class and add properties with the same names as the returned columns.
public class PersonWithAddress
{
public int Id { get; set; }
public String Name { get; set; }
public String Address { get; set; }
}
And the C# with parameters
MyEntity db = new MyEntity();
String sqlQuery = #"
SELECT Id, Name, Address
FROM Person p
JOIN Address a
ON a.Id = p.Id
WHERE Name = #Name
AND Address = #Address
";
String searchName = "Joe";
String address = "123 Something Lane";
DbRawSqlQuery<PersonWithAddress> results = db.Database.SqlQuery<PersonWithAddress>(
sqlQuery,
new SqlParameter("#Name", searchName),
new SqlParameter("#Address", address)
);
foreach(PersonWithAddress a in results)
{
}
You can list as many parameters as you want.
Wow this question's 2 years old. I didn't even realize that.
I have been building a Motion Picture application to manage actors or "Talents". I have a TALENT table and a LANGUAGES table. I also have a TALENTLANGUAGES table that shows the many to many relationship between the two.
Here is the SQL i can write to show the different languages a given talent speaks.
Select t.TalentID, t.FirstName, tl.LanguageID, l.Name from Talent t
inner join TalentLanguage tl on tl.TalentID = t.TalentID
inner join Language l on l.LanguageID = tl.LanguageID
where t.TalentID = 10000;
Im in my C# application I'm using Linq to sql classes. How might I do the above code with linq to sql. Thanks.
Here's one way you can do it:
Start by creating a "results" object, something that will hold the information that you need in one object. Let's call it "TalentLanguagesContainer"
public class TalentLanguagesContainer
{
public int TalentID { get; set; }
public string FirstName { get; set; }
public int LanguageID { get; set; }
public string LanguageName { get; set; }
}
Then, create a Select statement that will map your needs appropriately:
public IQueryable < TalentLanguagesContainer > GetTalentLanguages()
{
MyDataContext _dataContext = new MyDataContext();
return _dataContext.TalentLanguages
.Where(t => t.TalentID == 10000)
.Select(tl => new TalentLanguagesContainer() {
TalentID = tl.TalentID,
FirstName = tl.Talent.FirstName,
LanguageID = tl.LanguageID,
LanguageName = tl.Language.Name });
}
Also, you may want to consider writing stored procedures for more complex scripts such as this one - you may find an SQL script to perform faster too.
Remus, I think I'm gonna answer this myself because it's such a clean solution. Check this out...
var languages = from tl in talentDB.TalentLanguages
where tl.TalentID == id
select new { lang = tl.Language.Name, tal_id = tl.TalentID }; // could get more values if needed..
foreach (var l in languages)
{
string language = l.lang;
string talentID = l.tal_id;
// etc...
}
This is pretty cool! Linq did the join for me!!
Context: ASP.NET MVC 2.0, C#, SQL Server 2008, IIS7
I have 'scheduledMeetings' table in the database.
There is a one-to-many relationship: scheduledMeeting -> meetingRegistration
So that you could have 10 people registered for a meeting.
meetingRegistration has fields Name, and Gender (for example).
I have a "calendar view" on my site that shows all coming events, as well as gender count for each event.
At the moment I use Linq to Sql to pull the data:
var meetings = db.Meetings.Select(
m => new {
MeetingId = m.Id,
Girls = m.Registrations.Count(r => r.Gender == 0),
Boys = m.Registrations.Count(r=>r.Gender == 1)
});
(actual query is half-a-page long)
Because there is anonymous type use going on I cant extract it into a method (since I have several different flavors of calendar view, with different information on each, and I don't want to create new class for each).
Any suggestions on how to improve this?
Is database view is the answer?
Or should I go ahead and create named-type?
Any feedback/suggestions are welcome. My DataLayer is huge, I want to trim it, just don't know how.
Pointers to a good reading would be good too.
I'd extend your Meetings class by adding 2 properties:
public partial class Meeting
{
#region Properties
public int BoyCount { get; set; }
public int GirlCount { get; set; }
#endregion
}
With deferred loading:
var items = db.Meetings.Select(
m => new {
Meeting = m,
Girls = m.Registrations.Count(r => r.Gender == 0),
Boys = m.Registrations.Count(r = >r.Gender == 1)
}).ToList();
items.ForEach(i =>
{
i.Meeting.BoyCount = i.Boys;
i.Meeting.GirlCount = i.Girl;
});
List<Meeting> = items
.Select(i => i.Meeting)
.ToList();
With eager loading, one of the solutions is to load Registrations with your Meeting entity:
DataLoadOptions loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Meeting>(m = > m.Registrations);
db.LoadOptions = loadOptions;
In this case the partial class properties above are became getters:
public partial class Meeting
{
#region Properties
public int BoyCount
{
get
{
return this.Registrations
.Count(r => r.Gender == 1);
}
}
public int GirlCount
{
get
{
return this.Registrations
.Count(r = > r.Gender == 0);
}
}
#endregion
}