How to filter via laravel relationship - eloquent

Could someone help me if I can filter through laravel relationship in following scenario? I want to filter with the slip id / or customer_id/ or customer name.
public function search_index($query){
$slip = Slip::with('customer')
->where('slip_id',$query)
->orWhere('customer.id',$query)
->orWhere('customer.name',$query)->get();
}
Edit:
there are two classes: Slip and Customer. With the relations being slip belongs to customer and customer has many slips.
The slip contains other information including customer id and customer is retrieved using 'customer' relationship. Now I want to be able to find the slips by either entering customer name/id or slip id.
($query) may have one of those details
Slip::with('customer') returns details in following pattern:
[{slip:{id:1, ref:'abc', customer:{id:1,name:'Joe'}},}]
I want the query to return result in similar fashion too.
Thanks in advance

I haven't execute the code, but I pretty sure that this is gonna work.
$slip = Slip::query
->whereHas('customer', function(Builder $q) use ($query) {
return $q->where('id', $query) //Search by customer id
->orWhere('name', 'like', '%'.$query.'%'); //search by customer name similiarity
})
->orWhere('id', $query) //search by slip_id
->get();
This is not the best practice as I would suggest. It is recommended that you should break down the query in to 3 smaller functions/module, then get their intersect() as final result.

Related

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

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)

Entity Framework - best practice to get count

I have a Customer table and another Orders table. Each Customer can have many orders (One to many relationship).
I want to get a Customer object and from it get how many orders he has (the actual order data is not relevant at this point). So as I see it I have 2 options:
create a view with another OrdersCount field - and that will be another object in my system.
in my app, when I need the count get the Customer.Orders.Count - but for my understanding that will cause an extra query to run and pull all the orders from the database to that collection.
Is there a correct way to do such thing?
Thanks
You do need a new type, but you don't need to recreate all relevant properties.
from c in context.Customers
// where ...
select new {
Customer = c,
OrderCount = c.Orders.Count()
}
Update code that looks for e.g. the Name property of an item in the result, to look for Customer.Name.

Entity Framework code first aspnet_Users mapping / joins

I was wondering with Entity Framework 4.1 code first how do you guys handle queries that involve an existing aspnet_Users table?
Basically I have a requirement for a query that involves the aspnet_Users so that I can return the username:
SELECT t.Prop1, u.Username
FROM Table1 t
INNER JOIN aspnet_User u ON t.UserId = u.UserId
Where t.Prop2 = true
Ideally in linq I would like:
from t in context.Table1
join u in context.aspnet_Users on t.UserId equals u.UserId
where t.Prop2 = true
But I'm not sure how to get aspnet_Users mapping to a class User? how do I make aspnet_Users part of my dbset ?
Any help would be appreciated, thanks in advance
Don't map aspnet_Users table or any other table related to aspnet. These tables have their own data access and their own logic for accessing. Mapping these tables will introduce code duplication, possible problems and breaks separation of concerns. If you need users for queries, create view with only needed information like id, user name, email and map the view. The point is that view will be read only, it will contain only allowed data and your application will not accidentally modify these data without using ASP.NET API.
First read Ladislav's answer. If you still want to go ahead : to do what you want would involve mapping the users and roles and members tables into the codefirst domain - which means writing a membership provider in code-first.
Luckily there is a project for that http://codefirstmembership.codeplex.com/ although its not a perfect implementation. The original is VB, look in the Discussion tab for my work on getting it running in c# MVC.
I'm working with the author on a better implementation that protects the membership data (password, last logged on date, all of the non-allowed data) but allow you to map and extend the user table. But its not ready yet!
You don't really need to use Entity Framework to access aspnet_membership provider accounts. You really just need to create an instance of the membership object, pass in a unique user identifier and a Boolean value indicating whether to update the LastActivityDate value for the user and the method returns a MembershipUser object populated with current values from the data source for the specified user.
You can then access the username by using the property of "Username".
Example:
private MembershipUser user =
Membership.GetUser(7578ec40-9e91-4458-b3d6-0a69dee82c6e, True);
Response.Write(user.UserName);
In case you have additional questions about MembershipProvider, you can read up on it on the MSDN website under the title of "Managing Users by Using Membership".
Hope this helps you some with your requirement.

LLBLGEN related array not populating in entity

i'm struggling with LLBLGEN and i guess ORM's in general.
i have created an entity, lets use a library example to explain:
i want to display a book object and also return a list of users who have loaned the book.
so i need to return the book object which contains a list of users.
DTO Book::
int bookId,
string bookName
additionally i wish to return with my book a collection of users who have loaned the book:
List<user> Loans
loans table might look like this:
int id
int userid
int bookid
currently my loans entity has now created this:
DTO Loans
int id
User user // user entity
Book book // book entity
im struggling to understand how this example would work in llblgen. can anyone assist with guidance or point me in the way of a tutorial?
at the moment, when i come up to update my model Book with a new loan associated to a book, im getting stackoverflow errors. i assume this is creating some sort of loop when attempting to update my Book object.
thanks
i noticed when running a profiler on SQL that the sql statement didnt include any join statements onto my relationship entities.
this was because my domain query didnt include prefetch items for my relationships, i added the following to my query:
var query = new DomainSearch<T>
{
SearchText = searchText,
PrefetchItems =
{
new Prefetch(typeof(Users))
}
};
To make sure, you are looking for a list of User entities that have loaned a particular Book entity. Is this the correct use case, or are you looking for a list of User entities that have borrowed the particular book?
Regardless, LLBLGen's support for these cases is great with referencing relationships between entities and using related entities quickly and easily.
Presuming you're looking up a book by unique BookId/ISBN/etc....
// Get the specific book entity
BookEntity book = new BookEntity(bookId);
foreach(UserEntity user in book.users)
{
// do stuff with list of users
}
It's just that simple assuming you've defined your relationships between entities.

Multiple join query in eSql

This is my first question in stackoverflow but really not the first time to get solution here. I am struggling with multiple join in entity framework 4. I have three tables (Accounts, Users and AccountUsers) that am finding difficult to query.
What I want is to get all the users for the provided accountId including the account creator. I can get all the account users with no problem but the hard side for me is getting the account creator since it's not added to AccountUsers table. below is a quick preview how the tables are related.
Accounts
AccountId
UserId (account creator)
...other columns
Users
UserId
...other columns
AccountUsers
AccountId
UserId
I would prefer the query to be esql, but Linq to Entities will do.
I trust you guys on stackoverflow, so I know this won't take long to get the 'Answer' mark.
Thanks for even reading.
If I'm reading your question right, you're not looking for a join so much as a union? I'm not sure about esql, but I'd think the following Linq query should work. Maybe it will get you going in the right direction (or I could be completely off-base or missing something):
var users = (from accountUser in db.AccountUsers
where accountUser.AccountId == myAccountId
select accountUser.UserId)
.ToList()
.Add((from account in db.Accounts
where account.AccountId == myAccountId
select account.UserId)
.Single());
To make it lazy loading, you could always make a method that makes use of foreach and yield return:
IEnumerable<int> GetAccountUsers(int AccountId)
{
//return the users
foreach(var userId in (from accountUser in db.AccountUsers
where accountUser.AccountId == myAccountId
select accountUser.UserId))
yield return userId;
//return the owner too
yield return (from account in db.Accounts
where account.AccountId == myAccountId
select account.UserId)
.Single();
}
Out of curiosity, though, why is the owner not also added to the AccountUsers table?