Call to undefined method Illuminate\Database\Query\Builder::with() when retrieving orders with providers and services - eloquent

I am trying to retrieve orders with their service names and provider names all which are in a many to many relationship.
Additionally, I want to use joins to get the client, name.
I have thus used the code bellow
$orders = DB::table('orders')
->join('users', 'orders.user', 'users.id')
->select('users.name As client', 'orders.id', 'orders.amount As amount','orders.description As description', 'orders.status As status')
->with('providers')
->with('services')
->where(['orders.status'=>1])
->get();
In the Order model class, I have implemented the relationships as follows
public function providers()
{
return $this->belongsToMany(ServiceProvider::class)
->as('provider');
}
public function services()
{
return $this->belongsToMany(Service::class)
->as('service');
}
With this I am expecting to retrieve each order with all the services and providers related to it and since I have a foreign key user linking orders to users table, I have used joins to get the name of the user who placed the order as client. Now my problem is that this is not working and is giving the error above. Does this mean that the with() method does not exist in database query builder? if so what method can I use with database query builder to achieve this? Incase there is none, how can I use eloquent ORM to achieve the same purpose?

When you use the DB::table() method, you are not using your Models, so the ->with() method, which is used to include Relationships is not available. To handle this, please use your Models:
$orders = Order::join('users', 'orders.user', 'users.id')
->select('users.name As client', 'orders.id', 'orders.amount As amount','orders.description As description', 'orders.status As status')
->with(['providers', 'services'])
->where('orders.status', 1)
->get();
Additional fixes:
The ->with() method can accept an Array of relationships to include:
->with('providers')->with('services') can be written as ->with(['providers', 'services'])
The where() method can accept an array for multiple where clauses, but is unnecessary for a single where clause:
->where(['orders.status'=>1]) is the same as ->where('orders.status', 1)

Related

Spring JPA Specification API with custom Query and custom response Object. Is this possible?

I have researched this for a few days but can't seem to find the right information.
Here is what I need, I have a Database, with multiple tables, I need to join a few tables together to make a sort of "search" API. I have to implement the ability to dynamically search fields (from various tables in the query), sortable, with pagination.
I have found that I cannot combine the #Query annotation with Specification API, and I looked into using the specification API to do the joins I needed but, the problem is the root must be one table/repository.
For example:
If I have a users table that has to join on addresses, phone_numbers, and preferences
the base repository will be UserResposiory and it will return the User entity model, but I need it to return a custom DTO
AccountUserDTO which contains fields from the User, Address, PhoneNumber, and Preference entities.
Would anyone know if this is possible at all??
I am at wits end here and I really want to build this the correct way.
Cheers!
You may do this way:
Build hql query as an string, depend on how the filter condition is requested, you can build the corresponding query, eg:
if (hasParam(searchName)) {
queryString = queryString + " myEntity.name = :queryName"
}
Query query = session.createQuery(queryString);
and the parameter providing
if (hasParam(searchName)) {
query.setParameter("queryName", searchName);
}
...
and execute it.
To create a customized object, the easiest way is treating the object as an array of field:
Query query = session.createQuery("select m.f1, m.f2, m.f3 from myTable m");
List managers = query.list();
Object[] manager = (Object[]) managers.get(0); //first row
System.out.println(manager[0]) //f1
System.out.println(manager[1]) //f2
System.out.println(manager[2]) //f3
There is also some other solution to select, such as
String query = "select new mypackage.myclass(m.f1, m.f2, m.f3) from myTable m";
-> And when execute the above query, it will return a list of object.
Or to be simpler, make your own view in db and map it to one entity.

Laravel eloquent join multiple table and search data using with() method

I have two table user and user_info. I need to join those table and have to search data from them. It is throwing error as unknown column.I have solution using DB query, Is it possible to do search using with() method in controller and eloquent relationship in model.
Thank you
It's not possible to filter models by their related models attributes using with() - this method only allows filtering related models, not the original ones you're loading.
In order to filter by attributes of related models you should use whereHas() method, e.g. in order to load all users that have country column set to uk in their user_info data you could do the following:
$usersFromUK = User::with('user_info')->whereHas('user_info', function($query) {
$query->whereCountry('uk');
})->get();

Eloquent Friendly Column Name

We're currently transitioning from one database to another. A table in our legacy database has column names that are less than ideal, for example:
some_crazy_name__xyz
In our new database, we'd like to have a column name like:
someCrazyName
In the short term, we have to work with data from our legacy database. At some point in the near future, we'd like to switch over without having to refactor all of our Eloquent code to query for different column names. For example:
$model = MyModel::where('someCrazyName', '=', 1);
I'm currently extending the Model class, where all implementing models provide a map of terrible names to friendly names:
class MyModel extends BaseModel {
$columnMap = array(
'someCrazyName' => 'some_crazy_name__xyz'
);
}
This works well where I can use __get and __set in BaseModel to lookup properties in my map, for example:
$myModel = new MyModel;
// ...
echo $myModel->someCrazyName;
However, this obviously doesn't work well with queries without having to always use my map to look up column names. I'm wondering if it's possible without having to override all of the methods within Illuminate\Database\Eloquent\Model, Illuminate\Database\Query\Builder and Illuminate\Database\Eloquent\Builder that deal with columns, where the underlying query that is built always maps to the correct column? Then after we transition databases, we can remove that one piece of code rather then remove potentially thousands of column name mappings.
This is what you need: https://github.com/jarektkaczyk/eloquence/wiki/Mappable
It's not only for mapping badly_named_columns to something_useful, but also can be used for relational mappings:
// simple aliasing
User::where('cool_name', 'value') // where badName = ?
// relations, eg. User hasOne Profile
User::where('first_name', 'Jon') // search through related profiles table
// and obviously mutators:
$user->first_name == $user->profile->first_name
$user->cool_name = 'Jon' // becomes $user->badName = 'value'
$user->cool_name; // 'Jon'
One way to do it would be with accessors.
For example, in MyModel you could define an accessor for the some_crazy_name__xyz column like this:
public function getSomeCrazyNameAttribute()
{
return $this->attributes['some_crazy_name__xyz'];
}
You can then transparently refer to that column with $mymodel->someCrazyName. You can also define a mutator to set the value.
Admittedly, this may not be the best solution if you have MANY values like this. But it does have one important benefit: later on, if you refactor your database so that the column some_crazy_name__xyz is actually called someCrazyName, all you need to do is remove that function from your model. And, to my mind at least, it's simpler than trying to override a bunch of methods on the various classes involved.
And unfortunately, it doesn't adequately address the use of column names in queries. For that, you might want to look at the repository pattern. But in any event, it looks like there's going to be a lot of coding involved.
Finally, you haven't mentioned what database you're using. If it's MySQL, it is possible to create updatable and insertable views. Using a view, you could simply map old column names to new, and point your Eloquent model at the view instead of a table. Other database servers may provide similar functionality.

How to use model with multiple identical tables, for data isolation?

I am writing a simple SaaS application for small construction companies to use and am trying to achieve mid-level data isolation by having each company have their own unique data tables that aren't shared.
This is also nice in case the WHERE {group_id} clause is missing, other group data won't be exposed.
I am able to use the command builder to create these tables dynamically, prefixing them with the group number like grp_37645_projects.
But I am stuck on how to use my model classes as the table names change.
After login, I want to set the table names. These won't change as users aren't allowed to be a part of more than one group.
I have read about changing the tableName, but that is a STATIC function, and I have read a little about creating classes on the fly, but neither option was detailed or complete.
I also know this touches on the single table inheritance, but once again, every example use a little different scenario.
Do you have a recommended solution for setting the tableNames dynamically?
Add some logic for tableName:
namespace app\models;
use yii\db\ActiveRecord;
class Project extends ActiveRecord
{
/**
* #return string the name of the table associated with this ActiveRecord class.
*/
public static function tableName()
{
//some logic for getting current "group_id" for current user
$current_group_id = \Yii::$app->user->identity->group_id;
return 'grp_'.$current_group_id.'_projects';
}
}

Attempting to use EF/Linq to Entities for dynamic querying and CRUD operations

(as advised re-posting this question here... originally posted in msdn forum)
I am striving to write a "generic" routine for some simple CRUD operations using EF/Linq to Entities. I'm working in ASP.NET (C# or VB).
I have looked at:
Getting a reference to a dynamically selected table with "GetObjectByKey" (But I don't want anything from cache. I want data from database. Seems like not what this function is intended for).
CRM Dynamic Entities (here you can pass a tablename string to query) looked like the approach I am looking for but I don't get the idea that this CRM effort is necessarily staying current (?) and/or has much assurance for the future??
I looked at various ways of drilling thru Namespaces/Objects to get to where I could pass a TableName parameter into the oft used query syntax var query = (from c in context.C_Contacts select c); (for example) where somehow I could swap out the "C_Contacts" TEntity depending on which table I want to work with. But not finding a way to do this ??
Slightly over-simplyfing, I just want to be able to pass a tablename parameter and in some cases some associated fieldnames and values (perhaps in a generic object?) to my routine and then let that routine dynamically plug into LINQ to Entity data context/model and do some standard "select all" operations for parameter table or do a delete to parameter table based on a generic record id. I'm trying to avoid calling the various different automatically generated L2E methods based on tablename etc...instead just trying to drill into the data context and ultimately the L2E query syntax for dynamically passed table/field names.
Has anyone found any successful/efficient approaches for doing this? Any ideas, links, examples?
The DbContext object has a generic Set() method. This will give you
from c in context.Set<Contact>() select c
Here's method when starting from a string:
public void Test()
{
dynamic entity = null;
Type type = Type.GetType("Contract");
entity = Activator.CreateInstance(type);
ProcessType(entity);
}
public void ProcessType<TEntity>(TEntity instance)
where TEntity : class
{
var result =
from item in this.Set<TEntity>()
select item;
//do stuff with the result
//passing back to the caller can get more complicated
//but passing it on will be fine ...
}