I am having issues trying to query an Eloquent relationship.
I have 2 tables
tbl_deals
id
deal_id
merchant_id
tbl_merchants
id
merchant_id
merchant_url_text
I defined a deal model as
class deal extends Model
{
public function merchant() {
return $this->hasOne('App\merchant', 'merchant_id', 'merchant_id');
}
}
Now, I want to query all deals based where merchant_url_text = a variable in my controller
Here's what I am trying
$deals = deal::with('merchant')->get(); //Retrieving all the deals with merchants
If I return $deals its giving me all deals with merchant relationship.
How do I constraint the deals by saying where merchant_url_text = $variable
I am trying
return $deals->where('merchant_url_text', $merchant_url_text)->get();
but it is giving me an error saying :
"Missing argument 1 for Illuminate\Support\Collection::get(), called in ..."
I tried to lookup the documentation for querying relationships in Laravel Docs. It talks about this example
$user = App\User::find(1);
$user->posts()->where('active', 1)->get();
In this case, its trying to get the first user and finding corresponding posts related to the user.
In my case I want to filter from all deals, the deals that have merchant_url_text = a specific variable in my controller.
Any help on how I can achieve this?
Thanks
Try the following code :
$specific_merchant_url_text = "i don't know";
$deals_with_specific_merchant_url_text = [];
$deals = deal::with('merchant')->get();
foreach($deals as $deal)
if( $deal->merchant->merchant_url_text==$specific_merchant_url_text)
array_push($deals_with_specific_merchant_url_text, $deal);
So you get array of deals with specific merchant url text in deals_with_specific_merchant_url_text.
Another approach using DB object :
$deals = DB::table('deals')
->join('merchants', 'deals.merchant_id', '=', 'merchants.id')
->select('deals.*')
->where('merchants.merchant_url_text', $merchant_url_text)
->get();
Yours with raw :
$deals = deal::selectRaw('tbl_deals.*')
->Join('merchants','deals.merchant_id','=','merchants.merchant_id')
->where('merchants.merchant_url_text', '=', $merchant_url_text) ->get();
Hope this helps.
With takes a callback. This will bring back all deals but only eager load merchants that match.
$deals = Deal::with(['merchant' => function ($query) use ($url_text){
return $query->where('merchant_url_text', $url_text);
}])->get();
Flip-side: if you only want deals with a matching merchant, use where has.
$deals = Deal::whereHas('merchant', function ($query) use ($url_text){
return $query->where('merchant_url_text', $url_text);
})->get();
If you want both, chain them:
$deals = Deal::whereHas('merchant', function ($query) use ($url_text){
return $query->where('merchant_url_text', $url_text);
})->with(['merchant' => function ($query) use ($url_text){
return $query->where('merchant_url_text', $url_text);
}])->get();
I capitalized deal because it's standard. It wasn't capitalized in your example.
You can use query builder join query .
DB::table('tbl_merchants')
->join('tbl_deals', 'tbl_merchants.merchant_id', '=','tbl_deals.merchant_id')
->where('tbl_merchants.merchant_url_text',$merchant_url_text)
->get();
Related
How can I pass variable holding a value instead of passing a value directly to groovy search criteria?
for (def payee in payees)
{
def results = resp.cases.find("eq 'hrid','7547') // hard code values work
def results = resp.cases.find("eq 'hrid',??????) // how can I pass payee
}
I'm new to this. Please help. thanks
Basing on examples, check it:
def results = resp.cases.find { case -> case.hrid == payee }
GORM criteria queries are quite different than your example. Let's say you have a Payee domain class with a property named hrid:
grails-app/domain/com/something/Payee.groovy
class Payee {
String hrid
}
To get a list of all the Payee instances with an hrid of 7547, you'd run a criteria query like this:
String hridValue = '7547'
List payees = Payee.withCriteria {
eq 'hrid', hridValue
}
I explain Grails GORM queries in depth in a series of articles starting right here.
I'm looking for the way how to get all statements from my model by its property and by a class of an object.
For example I have property :driverOf and individuals either of type Bus or Truck. Then I want to get all statements where the property is :driverOf and the object is instanceOf Bus. Thanks.
UPDATE 1
Actually I need the result to be a set of statements (resp. StmtIterator) because in my app I use statement objects already. I think the most clean solution would be to have subproperties of :driverOf property, something like :driverOfBus and :driverOfTruck. But it would make my app more complicated, so I would like to find out some simple workaround.
You could use sparql query. You have to replace labels with full namespaces.
String queryString =
"SELECT ?x WHERE { ?x driverOflabel ?y . {?y a Buslabel} UNION { ?y a Trucklabel} . }";
Query query = QueryFactory.create(queryString);
QueryExecution qexec = QueryExecutionFactory.create(query, YOURMODEL);
try {
ResultSet results = qexec.execSelect();
while(results.hasNext()) {
QuerySolution soln = results.nextSolution();
System.out.println(soln.toString());
}
} finally {
qexec.close();
}
I hope i understood this correctly:
Say you have model m and namespace NAMESPACE
// Get the property and the subject
Property driverOf = m.getProperty(NAMESPACE + "driverOf");
Resource bus = m.getResource(NAMESPACE + "bus");
// Get all statements/triples of the form (****, driverOf, bus)
StmtIterator stmtIterator = m.listStatements(null, driverOf, bus);
while (stmtIterator.hasNext()){
Statement s = stmtIterator.nextStatement();
Resource busDriver = s.getObject();
// do something to the busdriver (only nice things, everybody likes busdrivers)
}
In my Person table is a RequestedLocation column which stores location IDs. The IDs match the LocationId column in the Locations table, the Locations table also has the text location names, in the LocatioName column.
In my view, I need to display the string LocationName in the view which has the Person model passed to it. The view will be displaying a List of people in a telerik grid. CUrrently it works great, except the RequestedLocation column is all integers.
I am populating all my grids with methods containing LINQ queries. Here is the method that currently works:
public List<Person> GetPeople()
{
var query = from p in _DB.Person.ToList()
select p;
return query.ToList();
}
Here is the regular SQL query that works, and I need to convert into LINQ:
SELECT ApplicantID
,FirstName
,LastName
,MiddleName
,DateofBirth
,Gender
,RequestedVolunteerRole
,RequestedVolunteerLocation
,l.LocationName
FROM Form.Person p
JOIN dbo.Location l ON p.RequestedVolunteerLocation = l.LocationID
Order BY ApplicantID
Here is my attempt to convert to LINQ:
public List<NewApplicantViewModel> GetPeople()
{
var query = from pl in _DB.Person.ToList()
join l in _Elig_DB.Locations.ToList() on pl.RequestedVolunteerLocation equals l.LocationID
select new
{
pl.RequestedVolunteerLocation = l.LocationName
};
return query.ToList();
The number of errors I get from this are numerous, but most are along the lines of:
Cannot convert from type Annonymous to Type List<NewAPplicantModel>
and
Invalid annonymous type declarator.
Please help, and thank you for reading my post.
Oh, and I have only been programming for a couple months, so if I am going about this all wrong, please let me know. Only thing I have to stick with is the table structure because it is an existing app that I am updating, and changing the location or person tables would have large consequences.
public List<NewApplicantViewModel> GetPeople()
{
var query = from pl in _DB.Person
join l in _Elig_DB.Locations on pl.RequestedVolunteerLocation
equals l.LocationID
select new NewApplicantViewModel
{
LocationName = l.LocationName,
otherPropery = p.Property
};
return query.ToList();
}
Beware of calling _DB.Person.ToList() it will load all persons from DB because ToList() immediately executes the query and the join would be performed in memory (not in DB).
The reason you are getting an error is you are projecting an anonymous type
select new
{
pl.RequestedVolunteerLocation = l.LocationName
};
Instead, you need to project a NewApplicantViewModel
select new NewApplicantViewModel
{
RequestedVolunteerLocation = l.LocationName
};
I'm designing an interface where the user can join a publicaiton to a keyword, and when they do, I want to suggest other keywords that commonly occur in tandem with the selected keyword. The trick is getting the frequency of correlation alongside the properties of the suggested keywords.
The Keyword type (EF) has these fields:
int Id
string Text
string UrlString
...and a many-to-many relation to a Publications entity-set.
I'm almost there. With :
var overlappedKeywords =
selectedKeyword.Publications.SelectMany(p => p.Keywords).ToList();
Here I get something very useful: a flattened list of keywords, each duplicated in the list however many times it appears in tandem with selectedKeyword.
The remaining Challenge:
So I want to get a count of the number of times each keyword appears in this list, and project the distinct keyword entities onto a new type, called KeywordCounts, having the same fields as Keyword but with one extra field: int PublicationsCount, into which I will populate the count of each Keyword within overlappedKeywords. How can I do this??
So far I've tried 2 approaches:
var keywordCounts = overlappingKeywords
.Select(oc => new KeywordCount
{
KeywordId = oc.Id,
Text = oc.Text,
UrlString = oc.UrlString,
PublicationsCount = overlappingKeywords.Count(ok2 => ok2.Id == oc.Id)
})
.Distinct();
...PublicationsCount is getting populated correctly, but Distinct isn't working here. (must I create an EqualityComarer for this? Why doesn't the default EqualityComarer work?)
var keywordCounts = overlappingKeywords
.GroupBy(o => o.Id)
.Select(c => new KeywordCount
{
Id = ???
Text = ???
UrlString = ???
PublicationsCount = ???
})
I'm not very clear on GroupBy. I don't seem to have any access to 'o' in the Select, and c isn't comping up with any properties of Keyword
UPDATE
My first approach would work with a simple EqualityComparer passed into .Distinct() :
class KeywordEqualityComparer : IEqualityComparer<KeywordCount>
{
public bool Equals(KeywordCount k1, KeywordCount k2)
{
return k1.KeywordId== k2.KeywordId;
}
public int GetHashCode(KeywordCount k)
{
return k.KeywordId.GetHashCode();
}
}
...but Slauma's answer is preferable (and accepted) because it does not require this. I'm still stumped as to what the default EqualityComparer would be for an EF entity instance -- wouldn't it just compare based on primary ids, as I did above here?
You second try is the better approach. I think the complete code would be:
var keywordCounts = overlappingKeywords
.GroupBy(o => o.Id)
.Select(c => new KeywordCount
{
Id = c.Key,
Text = c.Select(x => x.Text).FirstOrDefault(),
UrlString = c.Select(x => x.UrlString).FirstOrDefault(),
PublicationsCount = c.Count()
})
.ToList();
This is LINQ to Objects, I guess, because there doesn't seem to be a EF context involved but an object overlappingKeywords, so the grouping happens in memory, not in the database.
I have a simple many to many relationship and I am wondering how you get data out of it. Here is the setup
Tables
Media
Media_Keyword (many to many map)
Keyword
Here is the code I have:
public List<Keyword> GetFromMedia(int mediaID)
{
var media = (from m in Connection.Data.Media
where m.id == mediaID
select m).First();
var keys = (from k in media.Media_Keyword
select new Keyword {ID = k.Keywords.id, Name = k.Keywords.keyword});
return keys.ToList();
}
Is there a way to do this better?
Usually, I select right from the many-to-many map.
var keys = from k in Connection.Data.Media_Keyword
where k.MediaID == mediaID
select k.Keywords;
I've not used the entity framework specifically, but can't you just combine them like this?
public List<Keyword> GetFromMedia(int mediaID)
{
return (from m in Connection.Data.Media
from k in m.Media_Keyword
where m.id == mediaID
select new Keyword {ID = k.Keywords.id, Name = k.Keywords.keyword}).ToList();
}
Response to Kleinux (Don't know why i can't add a comment to your question)
Sure you can, but it's not necessarly a good things, because context giving you a new "keyword". Then, if you try to update this or something thinking that you will update, context gonna see it as a new keyword and would create a new one instead of updating it.
** UPDATE
Sorry for my english, i'm french, well not french but from Quebec. I'm giving my 110%!!