ActiveRecord relational order by - castle-activerecord

How can I perform I relational order by query? Let's say I have a class call Car which has a Property called Person which is another model. Person has a property called name. I want to get all cars but order by the persons names. The search should be something similar to this but working
var order = new Order[] { new Order("Person.Name", true) };
return FindAll(order);

I think it's supposed to be:
var order = new Order[] { Order.Asc("Person.Name", true) };

Related

Filter via condition on one relation and eager load another relation records

I have this code I want to get list users with a role of teacher where each teacher will have one object for the personal detail one object for the school detail
public function index(){
$teachers = User::whereHas('roles' , function($q){$q->where('name','isTeacher');})->get();
foreach($teachers as $teacher){
$teacher_id = $teacher->id;
$teacherinSchool = School_Teachers::where('user_id', $teacher_id)->first();
$teacherinSchool = $teacherinSchool->school_id;
$School = School::where('id', $teacherinSchool)->first();
return response(['teacher'=>$teacher, 'school'=>$School]);
}
}
this is what i got but i am expecting to have more that one teacher but it takes the first teacher in the list and display the objects
output in the postman
i have 5 models involved here User model, Role model, User_Role model, school model and school_teacher model
Few things to point out
You are doing queries within a loop (foreach) not good for performance.
Having return response() within foreach loop hence only 1 Teacher record is available
You are getting just the first record for School_Teachers & School
For what you are trying to do can be done more efficiently as under
public function index()
{
$teachers = User::whereHas('roles', fn($query) => $query->where('name', 'isTeacher'))->get();
$schoolIds = School_Teachers::whereIn('user_id', $teachers->pluck('id')->toArray())->pluck('id')->toArray();
$schools = School::whereIn('id', $schoolIds)->get();
return response()->json(['teachers' => $teachers, 'schools' => $schools]);
}
However that is also not optimal, still can be better
Define a relation on User model to link it to School model via School_Teachers (many-to-many)
Then in a single query you can get User(s) which have role of isTeacher with their School
For eg: Say you have a table school_teachers which has columns for user_id, school_id (kind of pivot table) where each record can be uniquely identified by ['user_id', school_id'] composite key - unique index on database table.
Then you can define direct (many-to-many) relation between User and School
//User model
public function schools()
{
return $this->belongsToMany(School::class, 'school_teachers', 'user_id', 'school_id');
}
//School model
public function teachers()
{
return $this->belongsToMany(User::class, 'school_teachers', 'school_id', 'user_id');
}
In controller you can do
public function index()
{
$teachers = User::with('schools')
->whereHas(
'roles',
fn($query) => $query->where('name', 'isTeacher')
)
->get();
return response()->json(['teachers' => $teachers]);
}
Laravel Docs - Eloquent Relationships - Many-to-Many

Applying filter to a dropdown list - ngoptions

I have a method that returns the list of custom types, those values are being used in both the dropdown lists, but now I want to remove a subset of them based on the type and then add to first drop down. I am using angular js, asp.net mvc. What is the best way to apply filter even before data is being rendered and keeping the same method.
Below is the method in the controller which returns names and departments as a json response. Now I want this method to return two different json objects one with subset of the current set being returned based on department they belong to.
Public JsonResult GetDetails()
{
List<Cust> Customers = new List<Cust>();
Customers = GetCustomerDetails();
var name = Customers.Select(e => new{e.custname}).Distinct().ToList();
var dept = Customers.Select(e => new{e.deptname}).Distinct().ToList();
var response = new{CustomerNames = name, CustomerDepartments = dept};
return Json(response, JsonRequestBehaviour.AllowGet();
}

How to update model by id in Backbone.js?

I've tried simple example from backbone tutorial and can't get this working
var Person = Backbone.Model.extend({});
var People = Backbone.Collection.extend({
model: Person,
url: "http://localhost:3002/people"
});
var people = new People();
var person = new Person({
id: 3
});
person.fetch({
success: function () {
person.set({age: 23});
person.save();
}
});
I just want to update existing record with id equals to 3 but got an error A "url" property or function must be specified. I'm sure that I didn't make mistake when typing this example but it works in tutorial and doesn't work for me. Is it because of some version changes?
As the error and comments have indicated, you need to specify the url property for the model or add the person model the people collection.
If you would like to fetch your model using the same url as the people collection. You need to add person to the people collection by doing:
var people = new People(person);
// or
people.add(person);
// The fetch url for a person would look like
// GET http://localhost:3002/people/3 Assuming the id of the person is 3.
If you need to use a different url than your collection has specifed the person model. You can specify the url or urlRoot attribute in your Person model.
var Person = Backbone.Model.extend({
urlRoot:'http://localhost:3002/person'
});
// The fetch url for a person would look like
// GET http://localhost:3002/person/3 The number will match id of model.

Apex Trigger Context Variable

Here my code for apex trigger.
trigger LeadTrigger on Lead (after insert)
{
if(Trigger.isInsert){
for(Lead newLead: Trigger.new)
{
//newLead.RecrodTypeId //'Give value of record type id.
//newLead.RecordType.Name //'Null'
}
}
}
Why "newLead.RecordType.Name" returns null?
The lists of objects available in triggers only have values for the fields on the object the trigger is running on. No relationships are traversed, only the IDs of the lookup records are included.
Therefore, to pull in any extra information you need to from related objects needs to be queried for.
You'll want to do something like this:
trigger LeadTrigger on Lead (after insert) {
map<id, RecordType> mapRecordTypes = new map<id, RecordType>();
if(Trigger.isInsert) {
for(Lead newLead: Trigger.new) {
mapRecordTypes.put(newLead.RecordTypeId, null);
}
}
for(RecordType rt : [select Id, Name from RecordType
where Id in : mapRecordTypes.ketSet()]) {
mapRecordTypes.put(rt.Id, rt);
}
for(Lead newLead : Trigger.new) {
string recordTypeName = mapRecordTypes.get(sLead.RecordTypeId).Name;
}
}
This is probably because some of your leads that just got inserted don't have record types associated with them. This is normal. You can enforce that record type selection is mandatory through configuration, if that's what you're looking for.
[EDIT]
Now I think I understand the issue (from your comment). The reason is that since you're in a trigger, the associated RecordType referenced object is not available. The RecordTypeId will always be available since it is literally part of the trigger object as an Id. However, child objects (referenced objects) will not be available to simply reference from within a trigger. To do this you need to create a map of the referenced object in question by doing an additional SOQL call WHERE Id IN: theIdList.
From Apex, not in a trigger, you need to specifically call this field out from your SOQL like this:
List<Lead> leads = [SELECT Id, RecordType.Name FROM Lead];
What just happened there is that the child object, the RecordType in this case, was included in the query and therefore available to you. By default a trigger will not have all of your child objects pre-selected and therefore need to be selected afterwards from within the trigger or class called by the trigger:
List<Id> recIds = new List<Id>();
for(Lead l : leads)
{
recIds.add(l.RecordTypeId);
}
List<RecordType> rt = [SELECT Id, Name FROM RecordType WHERE Id IN :recIds];
Map <Id, String> idRecNameMap = new Map<Id, String>();
for(RecordType r : rt)
{
idRecNameMap.put(r.Id, r.Name);
}
// And finally...
for(Lead l : Trigger.new)
{
String tmpRecordTypeName = idRecNameMap.get(l.RecordTypeId);
}
I did not test this code but I think it look ok. Hope this makes sense.
you can't get extra information on the related objects from this trigger. if you want to get more information you need to make query for other objects.
List<RecordType> records = [SELECT Id, Name FROM RecordType WHERE Id = newLead.RecrodTypeId];
string myname = records[0].name;
but remember that you shouldn't make a query in for loop. so if you wanted to do it in the right way go for Adam's solution.
Put some system debug inside the loop and check your system debug logs for more information
system.debug('lead:' + newLead);
inside the for loop and see what is being passed in. You may find that it is null.
We cant really give you a good answer without knowint the rest of your set up.

How to avoid too many model classes

The number of models has grown quickly in my application. I'm wondering about your standard practices regarding backbone.js. Lets say you want to create a view that requires 2 other models. Do you create a new model class to contain the 2 models like this:
var m = new TheModel({
model1: new Model1,
model2: new Model2
});
var view = new TheView({model:m});
or do you just do something like:
var m = {
model1: new Model1,
model2: new Model2
};
var view = new TheView({model:m});
The second seems better because then I don't need the extra model class TheModel. But if I mix the two methods, then in my view I have to remember which style I'm using because if I want to get access to model1 or model2 then there are two different ways:
var m1 = this.model.get('model1');
or this way in the second scheme:
var m1 = this.model.model1;
Which is better in your opinion?? How do you organize all the models and views?
Thanks!
Unless there is a reason to link your models, I would not create a new model that aggregates other models. The second option is better because you are not linking them.
I prefer to separate them even further:
var view = new TheView({purchases: purchasesModel, user: userModel });
Then, inside the view, instead of referencing this.model, you reference this.purchases and this.user specifically.
You see, the model property on the views is really just a convention. There is nothing special about the model property in the view except that the model property will get copied automatically in the constructor. Other than that, there is no reference to the model in Backbone.View.
Of course, this means that you need to do something with it:
var TheView = Backbone.View.extend({
initialize: function(options) {
this.purchases = options.purchases;
this.user = options.user;
}
});
This way, you are being explicit about the multiple models that you require. I like this better than verison #2 because you are not as explicit about the requirements of the View.
You should use Collections in this case. Here you can read more about Collections: http://backbonetutorials.com/what-is-a-collection/

Resources