Issue understanding Salesforce Apex Trigger equality check inside in-line SOQL - triggers

I ran across this Apex Trigger code that I don't quite understand...
Id is, of course, an Id
hId is a SET
I would normally expect
"WHERE Id IN :hId", instead of
"WHERE Id = :hId"
trigger linkHusbandAndWife on h2w_c (after insert) {
Set<Id> hId = new Set<Id>();
for (h2w_c h2w : Trigger.New) {
hId.add(h2w);
}
List<Husband_c> husbandlist = [
SELECT Id Wife_Id
FROM Husband_c
WHERE Id = :hId
];
...
}
Question: How can "Id = :hId" when hId is a SET?
Is this somehow equivalent to "Id IN :hId" ?

Yes, the syntax for queries written in Apex is quite forgiving. Especially normal SOQL (written in [brackets], not the dynamic SOQL where you craft query from Strings) . It's more of Apex feature than SOQL, you might have been looking in wrong reference guide. The magic is in "bind variables" (:) and you can't always use same trick when making raw query via API for example.
WHERE Id = :collection is fine. Collection being a single variable of type Id, a Set or a List.
WHERE Id IN :collection has same result. And you don't even need parentheses!
This means your query can ditch the intermediary step of making a Set, less code to write:
SELECT Id, Wife_Id__c FROM Husband_c WHERE Id IN :trigger.new.
A List<sObject> will be silently "cast" to List<Id> for purposes of SOQL. I used quotes because normally you can't cast it, a sObject will never be an instance of Id. If you'd need similar behaviour in normal code you'd need something like Set<Id> mySet= new Map<Id, sObject>(mylist).keyset();.
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_SOQL_variables.htm
https://developer.salesforce.com/forums/?id=906F000000090b1IAA
https://salesforce.stackexchange.com/questions/17695/how-do-i-build-a-soql-query-for-records-in-a-list-of-ids

Related

Add SQL restriction to predicates in JPA query

I have to filter entities according to some parameters sent by client. For this purpose, i create a list of predicates like this:
List<Predicate> predicates = new ArrayList<Predicate>();
if (filters != null && StringUtils.hasText(filters.getName())) {
predicates.add(cb.like(cb.upper(root.get("name")),
"%" + filters.getName().trim().toUpperCase() + "%"));
}
//OTHER FILTERS
Now the problem is to add a criteria that is sql syntax. In particular i have to find entities that are located into a particular polygon. So i should add a restriction like this:
and within(point, :bounds) = true //bounds is the geometry drawn by client
I have read that i could use #Formula to define an sql filter but this annotation works everytime even if filter in input(about localization) is not setted.
Can anyone help me?
You should be able to call database functions using CriteriaBuilder.function(...). Try cb.equal(cb.function("within", Boolean.class, root.get("point"), bounds), cb.literal(true)).
This may or may not work out of the box depending on the type of the bounds parameter, because Hibernate needs to recognize it to know its SQL representation, though. You might need to create a custom LiteralType

RoR/Postgres Query for the first or last child object of all parents

I have seen similar questions, but no answers that match exactly what I need. If it's out there, I haven't seen it. I'm on Rails 3.1, Ruby 1.9.2, deployed on Heroku Cedar stack (so I'm using postgres)
I've got this model:
class User
has_many :orders
end
class Order
belongs_to :user
#scope :last_for_each_user, ???
#scope :first_for_each_user, ???
end
I need scopes (or methods) that return all orders that are all users' first orders, and all orders that are all users' last orders. My first instinct was to use GROUP BY, which worked fine for :last_for_each_user in SQLite3, but Postgres won't let you select columns that aren't in the GROUP BY clause or selected as part of aggregate functions, and I need fully formed orders objects (i.e., all of the columns, orders.*).
Any ideas? I don't want to select the whole table and sort it out in Ruby. That just doesn't feel right, and it's a lot to hold in memory.
So here's what I ended up doing, for future head-scratchers:
scope :last_for_each_user, lambda {
select("orders.*") & Order.select("max(orders.id) as id").group("orders.user_id")
}
scope :first_for_each_user, lambda {
select("orders.*") & Order.select("min(orders.id) as id").group("orders.user_id")
}
If anyone has a better idea, I am very much open to hear it. And thanks to the whole SO community (even though no one responded), this is the first time I've signed up/asked a question but every time I google a problem, I end up here!
You could use the DISTINCT ON() rules to get only the last one. Here's an example following your model structure:
scope :for_users, lambda {|ids, is_first| includes(:user).where("user_id IN (?)", ids).select("DISTINCT ON (users.id) *").order("orders.created_at ?", is_first ? : "ASC" : "DESC") }
scope :last_for_each_users, lambda { |users| for_each_users(users.map{|u| u.id }, false }
scope :first_for_each_users, lambda { |users| for_each_users(users.map{|u| u.id }, true }

wordpress 3.2.1 database query

i am trying to make a simple selection in a wordpress table (created by a plugin). the table is named reduceri , and has the following columns: id, post, category.
so, i am trying to take all the category values, when the post is equal to the current post id.
the way i am doing the query is:
$the_query = "
SELECT $wpdb->reduceri.category
FROM $wpdb->reduceri
WHERE $wpdb->reduceri.post = ".$post_id."
";
$my_reduceri = $wpdb->get_results($the_query);
but when i var_dump the $my_reduceri all i get is an empty array: array(0) { } even though there should actually be some results... any idea where i am wrong (in the query)?
thank you
Did you declared global $wpdb; before using this query?

Entity Framework Views and Linq .Where

I have a very small entity framework setup containing only a few related classes/tables and a view. I need to be able to pull a specific record from this view, namely, I need to be able to grab the record that meets two criteria, it has a specific ProfileID and a specific QuoteID.
This line is what's causing the problem:
TWProfileUpchargeTotal upchargeTotals = _context.TWProfileUpchargeTotals.Where(p => p.Profileid == profile.id && p.quoteid == _quote.quoteid).First();
I'm looping through the profiles I know about and getting their information from the view, so profile.id changes each time.
The first time this code executes it gets the correct record from the view.
The second and third (and presumably beyond that) time it executes, it retrieves the exact same record.
Any idea why or what I'm doing wrong here?
Thanks, in advance.
You've been bitten by the LINQ "gotcha" called closure. The following post (and many others) on SO detail this:
closure
What you need to do is declare a variable WITHIN the foreach you've ommited from the above code and assign the profile.id to this and use this in the Where clause.
foreach(Profile profile in ListOfProfiles)
{
var localProfile = profile;
TWProfileUpchargeTotal upchargeTotals = _context.TWProfileUpchargeTotals.Where(p => p.Profileid == localProfile.id && p.quoteid == _quote.quoteid).First();
}

Symfony: Model Translation + Nested Set

I'm using Symfony 1.2 with Doctrine. I have a Place model with translations in two languages. This Place model has also a nested set behaviour.
I'm having problems now creating a new place that belongs to another node. I've tried two options but both of them fail:
1 option
$this->mergeForm(new PlaceTranslationForm($this->object->Translation[$lang->getCurrentCulture()]));
If I merge the form, what happens is that the value of the place_id field id an array. I suppose is because it is waiting a real object with an id. If I try to set place_id='' there is another error.
2 option
$this->mergeI18n(array($lang->getCurrentCulture()));
public function mergeI18n($cultures, $decorator = null)
{
if (!$this->isI18n())
{
throw new sfException(sprintf('The model "%s" is not internationalized.', $this->getModelName()));
}
$class = $this->getI18nFormClass();
foreach ($cultures as $culture)
{
$i18nObject = $this->object->Translation[$culture];
$i18n = new $class($i18nObject);
unset($i18n['id']);
$i18n->widgetSchema['lang'] = new sfWidgetFormInputHidden();
$this->mergeForm($i18n); // pass $culture too
}
}
Now the error is:
Couldn't hydrate. Found non-unique key mapping named 'lang'.
Looking at the sql, the id is not defined; so it can't be a duplicate record (I have a unique key (id, lang))
Any idea of what can be happening?
thanks!
It looks like the issues you are having are related to embedding forms within each other, which can be tricky. You will likely need to do things in the updateObject/bind methods of the parent form to get it to pass its values correctly to its child forms.
This article is worth a read:
http://www.blogs.uni-osnabrueck.de/rotapken/2009/03/13/symfony-merge-embedded-form/comment-page-1/
It gives some good info on how embedding (and mergeing) forms work. The technique the article uses will probably work for you, but I've not used I18n in sf before, so it may well be that there is a more elegant solution built in?