Using relationships to search in DBIx::Class - perl

I am starting learning DBIx::Class and I have a doubt in searching in a related table:
Consider the following code:
my $books = $author->search_related('books', { name => 'Titanic' });
my $books = $author->books->search({name => 'Titanic'});
What I want is to only searches for books named 'Titanic' by the author in $author.
This two searches return the same resultset?
If yes, what is the best way and why?
If no, what is the difference?

search_related is a Resultset method. You'd use that if you had a resultset of Authors and you wanted to get a resultset of all of their books named 'Titanic'.
my $books = $schema->resultset('Author')->search({ last_name => 'Smith' })
->search_related('books', { name => 'Titanic' });
If $author is a row object, representing one row, then your second line is how you'd search his books.
my $books = $author->books->search({ name => 'Titanic' });
The distinction between rows and resultsets is one of the core concepts of DBIx::Class. You might want to review the DBIC Manual Intro. #dbix-class on irc.perl.org is usually pretty active so you can find help there as well.

Related

Query Combinaton

I am trying to build a query using asp.net core c#
https://www.reflectionit.nl/blog/2017/paging-in-asp-net-core-mvc-and-entityframework-core
I trying to do a filtering however I need the data from another table which have my unique id
var result = _context.UserRoles.Where(y => y.RoleId.Contains(selectedRoles.Id)); // Retrieve the the userid i have from another table with the selected roleid
var query = _context.Users.Where(x => //I have already tried contains, where join );
If there is a site where i can learn this query please recommend. "Join()" does not work as I am doing paging
a least two solutions (please note that I do not check the identity classes members, so the following is the "spirit" of the solution (you miss the select clauses) ):
var result = _context.UserRoles.
Where(y => selectedRoles.Contains(y.RoleId)).
Select(y => y.User);
or
var result = _context.UserRoles.
Where(y => selectedRoles.Contains(y.RoleId)).
Select(y => y.UserId);
query = _context.Users.
Where(x => result.Contains(x.Id));
That said, assuming that there is no UserRoles table exposed in Identity (v2), you probably want:
userManager.Users.
Where(u => u.Roles.Any(r => selectecRoles.Contains(r.RoleId)));
Up to you to instanciate the userManager.

Laravel eloquent search both table in one to many relationship table

My two table Member and Deposit there has one to many relationship one member has multiple deposit in Deposit table i want to search by multiple column both table which will have to match.
This is my Member Table
1.id,
2.branch_id,
3.village_id,
4.user_id,
5.name,
6.phone,
7.email,
8........
My Deposit Table
1.meber_id,
2.user_id
3.deposit_date,
4.deposit_amount,
5.total_amount,
6..........
My Controller Code
$depo = Deposit::with(['member'=>function($query){$query->where('branch_id',$request->branch_id)->where('status','running')->get();}])->where('user_id',$request->user_id)->whereDate('deposit-date','>=',$from_date)->whereDate('deposit-date','<=',$to_date)->get();
if i do that then ....$query->where('branch_id',$request->branch_id)->get()..... section is not working please help me any one
Try this:
$depo = Deposit::whereHas('member', function($query) use ($request){
$query->where([
['branch_id' => $request->branch_id],
['status'=> 'running']
])
})
->where('user_id',$request->user_id)
->whereDate([
['deposit-date','>=',$from_date],
['deposit-date','<=',$to_date]
])->get();
Your question is quite ambiguous, but looks like you need to use the $request in the with function.
$deposits = Deposit::with(['member' => function ($query) use ($request) {
$query->where('branch_id', $request->branch_id)
->where('status', 'running')->get();
}])->where('user_id', $request->user_id)
->whereDate('deposit-date', '>=', $from_date)
->whereDate('deposit-date', '<=', $to_date)
->get();
But the with method wont filter down your query it will simply limit the number of members returned with all the deposits. It's not searching in the member table.
UPDATE 04/12/2018
Without checking the docs at all, and completely off the top of my head.
Deposit::with('member', function($query) use($request){
$query->where('branch_id', $request->branch_id)
->orWhere('village_id', $request->village_id)
})->where(function($query) use($request) {
$query->where('user_id', $request->user_id)
->whereDate('deposit-date', '>=', $from_date)
->whereDate('deposit-date', '<=', $to_date)
})->orWhereHas('member', function($query) use($request){
$query->where('branch_id', $request->branch_id)
->orWhere('village_id', $request->village_id)
})->get();

Laravel Eloquent distinct values

PROBLEM SOLVED.
I'm trying to get an person's books, but there are more than one book in my book table since there are different editions of a book. When I list all books of a person, I shouldn't list duplicates.
Here's what I've done so far
Person Model
public function books() {
return $this->belongsToMany('\App\Models\Thing', 'bookxauthor', 'person_id', 'thing_id');
}
PersonController.php
$allbooks = Person::find($id)->books;
This is great, it lists all the books of an author, but I don't need duplicates.
The query below works. type_id means it's a book.
$findBooks = Person::with(array('books' => function($query)
{
$query->where('type_id',"=",3)->groupBy('original_name');
}))->find($id);
$allbooks = $findBooks->books;
You could use the groupBy function for collections
Eg.
$allbooks = Person::find($id)->books->groupBy('name')->get();
The query below works.
$findBooks = Person::with(array('books' => function($query)
{
$query->where('type_id',"=",3)->groupBy('original_name');
}))->find($id);
$allbooks = $findBooks->books;

Laravel and Eloquent: Specifying columns in when retrieving related items

This is a followup post to: Laravel 4 and Eloquent: retrieving all records and all related records
The solution given works great:
$artists = Artist::with('instruments')->get();
return \View::make('artists')->withArtists($artists);
It also works with just:
$artists = Artist::get();
Now I'm trying to specify the exact columns to return for both tables. I've tried using select() in both the statement above and in my Class, like this:
ArtistController.php
$artists = Artist::select('firstname', 'lastname', 'instruments.name')->get();
or:
$artists = Artist::with(array('instruments' => function($query) {
$query->select('name');
}))->get();
(as suggested here and while this doesn't throw an error, it also doesn't limit the columns to only those specified)
or in Artist.php:
return $this->belongsToMany('App\Models\Instrument')->select(['name']);
How would I go about getting just the firstname and lastname column from the artists table and the name column from instruments table?
Not sure what I was thinking. I think working on this so long got me cross-eyed.
Anyhow, I looked into this a lot more and searched for answers and finally posted an issue on GitHub.
The bottom line is this is not possible as of Laravel v4.1.
https://github.com/laravel/laravel/issues/2679
This solved it:
Artists.php
public function instruments() {
return $this->hasMany('App\Models\Instrument', 'id');
}
Note that I changed this to a hasMany from a belongsToMany which makes more sense to me as a musicians (or Artist) would have many Instruments they play and an Instrument could belong to many Artists (which I also alluded to in my previous questions referenced above). I also had to specify 'id' column in my model which tells the ORM that instrument.id matches artist_instrument.id. That part confuses me a bit because I thought the order for hasMany was foreign_key, primary_key, but maybe I'm thinking about it backwards. If someone can explain that a bit more I'd appreciate it.
Anyhow, the second part of the solution...
In ArtistsController.php, I did this:
$artists = Artist::with(array(
'instruments' => function($q) {
$q->select('instruments.id', 'name');
})
)->get(array('id', 'firstname', 'lastname'));
That gives me exactly what I want which is a collection of Artists that contains only the firstname and lastname columns from the artists table and the name column for each of the instruments they play from the instruments.
$artists = Artist::with(array('instruments' => function ($query) {
$query->select('id', 'name');
}))->get('id', 'firstname', 'lastname');

one to many join - taking only the last one on the many part

I'm quite a newbie in EF, so I'm sorry if my question has been answered before.. I just can't figure out the syntax..
I have two entities, Category & Product, where one category has many products.
I want to get all categories, with only their latest product (it has a date property named timestamp)
I have no idea how to do that. :-/
If possible I'd like to know the syntax of the two ways to write it, both the sql-like syntax, and the C# like syntax, e.g.:
ctx.Categories.Include("Products").ToList()
from c in ctx.Categories.Include("Products")
Thanks!
Here's the SQL-like way:
var categories =
from p in products
group p by p.Category into g
select new { Category = g.TheKey, LatestProduct = g.Max(p => p.TimeStamp) };
This is the Lambda-way (warning, untested):
var categories = products.GroupBy(p => p.Category)
.Select(g => new { Category = g.TheKey,
LatestProduct = g.Max(p => p.TimeStamp)});
A note on Categories.Include("Products"), you don't need this in your example. You use "Include" for eager-loading, so that for example if you had a list of Categories returned from EF, when you do Categories.Product you will get the associated product.
But all you require is a list of categories, and a single product for each one - which is already returned in the above LINQ query, so no need for Include.