Passing multiple arguments into a SELECT without using a complex object - ibatis

I am trying to pass in startSequenceId, stopSequenceId, orderNumber into the SQL map, however, i don't wish to use a typed object, i.e. parameterType="com.abc.Order", can i do so?
<select id="getSequenceIdByOrderNumber" parameterType="?" resultType="int">
select *
from log
where seq_id
between #{startSequenceId} and #{stopSequenceId}
and order_no = #{orderNumber}
and rownum = 1
</select>

You can use the built in parameterType 'map' eg
Map<String, Object> parms = new HashMap<String, Object>();
parms.put("name", "abc");
parms.put("phone", "123");
parms.put("email", "123#email.com");
List<Contact> list = myBatis.selectList("getContacts",parms);
<!-- in xml mapper -->
<select id="getContacts" parameterType="map" resultMap="Contact">
SELECT * FROM CONTACT
WHERE CONTACT_NAME = ${name}
AND CONTACT_PHONE = ${phone}
AND CONTACT_MAIl = ${email}
</select>

#Chin I'll post what I had typed anyway with a simple example though you found what your looking for. My example using iBatis 2.3.4
<select id="retrieveTestXXX" parameterClass="java.util.Map" resultClass="java.lang.Integer">
SELECT
example_table.id
FROM example_table
WHERE example_table.xx_id = #testId# AND example_table.xx_id = #test2Id#
</select>
Hope this helps.

In MyBatis 3, you can use #Param annotation in your mapper class(interface) method:
public getSequenceIdByOrderNumber(#Param("seqId") int sequenceId,#Param("orderId") int orderNo);
Then you can use #{seqId}, #{orderId} in the SQL without using parameterType attribute.

cant comment,
Found the answer, thanks.
http://code.google.com/p/mybatis/wiki/HowToSelectMultipleParams
this link is broken, currently correct one is https://github.com/mybatis/mybatis-3/wiki/FAQ#how-do-i-use-multiple-parameters-in-a-mapper
copy + paste from this wiki
Java reflection does not provide a way to know the name of a method parameter so MyBatis names them by default like: param1, param2...
If you want to give them a name use the #param annotation this way:
import org.apache.ibatis.annotations.Param;
public interface UserMapper {
User selectUser(#Param("username") String username, #Param("hashedPassword") String hashedPassword);
}
Now you can use them in your xml like follows:
<select id=”selectUser” resultType=”User”>
select id, username, hashedPassword
from some_table
where username = #{username}
and hashedPassword = #{hashedPassword}
</select>
tl;dr
when you declare method in your interface instead of standard java structure
Type methodName (
ParamType1 paramName1,
ParamType2 paramName2,
… ); (this is interface so no method body)
use (add #Param)
Type methodName (
#Param("name1 available in xml") ParamType1 paramName1,
#Param("name2 available in xml") ParamType2 paramName2,
…); (this is still interface so no method body)

Found the answer, thanks.
http://code.google.com/p/mybatis/wiki/HowToSelectMultipleParams

Related

How to find the API name of field from an label of field from a particular sobject?

How to find the API name of field from an label of field from a particular sobject.
This was pretty bad to find the field api name in salesforce, It is an indeed a trivial question which many of developer folks find out tough while working on projects.
Putting here as an code snippet for searching easily.
Here's the code snippet to find out the api name of the field based on the label of an object.
public static String getMyAPIName(String objectName, String fieldLabel ) {
SObjectType type = Schema.getGlobalDescribe().get(objectName);
Map<String,Schema.SObjectField> mfields = type.getDescribe().fields.getMap();
for(String strField : mfields.keySet())
{
SObjectField fl = mfields.get(strField);
if(fieldLabel == fl.getDescribe().getlabel())
{
return strField;
}
}
return '';
}
SELECT EntityDefinition.QualifiedApiName, QualifiedApiName, Label
FROM FieldDefinition
WHERE EntityDefinition.QualifiedApiName = 'Account' AND Label = 'Parent Account'
outputs "ParentId" just fine, no describes and loops

Get / Set entity when dealing with relation attribute

I'm working in a Wakanda environnement with the angular-wakanda connector.
Assume this model : Employee(firstName,lastName,company) and Company(name)
In the employee form, I have a select input that is filled with companies names (which is a entity collection).
I have set a ng-model="selectedCompany" in the select
When I select one company and perform a save, the value I get represent the value I have pass in the value of my option (ID or name).
When I assign the value to a new entity using the $create() method, I don't know which way to set the entity to the relation attribute. I assume that I have to give an entity. The thing is that I already have the entitycollection with all the entities. So I don't see the reason why should I query again the server just to assign somthing that I have already.
So the thing is that we should have a method like $find or $getById that will not do a request on the server but get the entity that is already loaded in the entityCollection. For now I use my own method that do a simple loop over my array. (I can share the code if anybody need it)
Am I missing a way to do that?
Assuming your selectedCompany variable contains an entity (of type Company), you only have to pass this variable on the $create() call with the property name like this:
var newEmployee = ds.Employee.$create({
firstName: 'foo',
lastName: 'bar',
company: $scope.selectedCompany
});
If selectedCompany contains only company name or ID, it's on you to have an array to map the companies with their name or ID. Something like that:
//When retrieving collection
var companyMap = [];
companies.forEach(function (company) {
companyMap[company.ID] = company;
}
//When you want your company with its ID
var company = companyMap[$scope.selectedCompany];
But the simplest way is the first, with your <select> directly iterating through entity collection, so that you can deal with entities.
Edit: Retrieving object with ng-option
To get the object on which you iterate on your select, you can use ng-option like this:
<select
ng-model="selectedCompany"
ng-change="companyChanged()"
ng-options="c.name for c in companies"
>
</select>
On the controller
$scope.selectedCompany = null;
$scope.companyChanged = function () {
if ($scope.selectedCompany) {
//selectedCompany is your company entity
//you can manipulate it like any other entity
$scope.selectedCompany.$save(); //for example
}
};
I think that your real problem is that you iterate on name/ID of each entity of company Collection.
This is the bad way to iterate on collections :
<select ng-model="selectedCompany" ng-options="company.nom as company.nom for i in collenctionOfCompanies">
<option value=""></option>
</select>
In this case selected company will contain only the name of the company.
But if you change your code as this :
<select ng-model="selectedCompany" ng-options="company as company.nom for i in collenctionOfCompanies">
<option value=""></option>
</select>
Then selectedCompany will contain the entity

Inserting image into visualforce email template (without hard-coding IDs)

The "official" solution for including images in visualforce email templates suggests hard coding IDs in your template to reference an image file stored as a document.
https://help.salesforce.com/HTViewHelpDoc?id=email_template_images.htm&language=en_US
Is there a better way that avoids hard coding instance ID and OID? I tried using the partner URL to grab the instance ID, but I got the following error
Error Error: The reference to entity "oid" must end with the ';' delimiter.
Using:
{!LEFT($Api.Partner_Server_URL_140,FIND(".com/",$Api.Partner_Server_URL_140)+3)/
to replace "https://na2.salesforce.com/"
in
"na2.salesforce.com/servlet/servlet.ImageServer?id=01540000000RVOe&oid=00Dxxxxxxxxx&lastMod=1233217920"
Should I use a static resource instead?
I've arrived here looking for an answer for this question related to hardcoded ID and OID in Visualforce e-mail templates. Well, I found a workaround for that.
First I needed to create a Visualforce Component:
<apex:component access="global" controller="LogomarcaController">
<apex:image url="{!LogoUrl}" />
</apex:component>
In the respective controller class, I've created a SFInstance property to get the correct URL Salesforce Instance, LogoUrl property to concatenate SFInstance and IDs... And Finally I've used Custom Settings (Config_Gerais__c.getInstance().ID_Documento_Logomarca__c) to configurate the ID of Image (in my case, Document Object) on Sandbox or Production:
public class LogomarcaController {
public String LogoUrl {
get {
id orgId = UserInfo.getOrganizationId();
String idDocumentoLogomarca = Config_Gerais__c.getInstance().ID_Documento_Logomarca__c;
return this.SfInstance + '/servlet/servlet.ImageServer?id=' + idDocumentoLogomarca + '&oid=' + orgId ;
}
}
public String SfInstance
{
get{
string SFInstance = URL.getSalesforceBaseUrl().toExternalForm();
list<string> Dividido = SFInstance.split('.visual', 0);//retira o restante a partir de .visual
SFInstance = dividido[0];
dividido = SFInstance.split('://',0);//retira o https://
SFInstance = dividido[1];
if(!SFInstance.contains('sybf')) //managed package prefix, if you need
{
SFInstance = 'sybf.'+ SFInstance;
}
return 'https://'+SFInstance;
}
}
}
And finally, I've added the component in Visualforce template:
<messaging:emailTemplate subject="Novo Ofício - {!relatedTo.name}" recipientType="User" relatedToType="Oficio__c" >
<messaging:htmlEmailBody >
<c:Logomarca />
</messaging:htmlEmailBody>
<messaging:plainTextEmailBody >
</messaging:plainTextEmailBody>
</messaging:emailTemplate>
PS: Some of my variables, properties and comments are in my native language (portuguese). If you have some problems understanding them, please ask me!
We ran into a similar problem and after trying various solutions, the following worked for us. In our case the image is uploaded as a content asset(https://help.salesforce.com/articleView?id=000320130&type=1&language=en_US&mode=1)
Solution:
<img src="{!LEFT($Api.Partner_Server_URL_260,FIND('/services',$Api.Partner_Server_URL_260))}/file-asset-public/<Image_Name_Here>?oid={!$Organization.Id}&height=50&width=50"/>

Debugging GQL Queries

I have been trying to run this query:
my_post = db.GqlQuery("SELECT * FROM Post where __key__ = KEY('Post', 1)")
self.render("showpost.html", my_post = my_post)
and my template showpost.html looks like this:
<div class="post">
<h3 class="post-subject">{{ my_post.subject }}</h3>
<div class="post-content">{{ my_post.content }}</div>
</div
Instead of getting the details of the Post of id=1 I'm getting a blank page. Although there exists a post with id=1 i'm not sure how to confirm if the GQLquery is actually returning something. Is there a way to check?
On trying the following:
my_post = db.GqlQuery("SELECT * FROM Post where subject = 'hello_world')
self.render("showpost.html", my_post = my_post)
I get the same issue (blank page), even though there is post who's subject is hello_world
Thanks a lot
GqlQuery is a class.
Your code has created an instance of the GqlQuery class.
To return something from the datastore you need to use either of the following instance methods:
.fetch() # requires number of entities as first argument
.get()
Example:
my_query = db.GqlQuery("SELECT * FROM Post WHERE subject = :subject",
subject="hello_world")
my_post = my_query.get() # the magic happens here
self.render("showpost.html", my_post = my_post)
Bernie is right in that you need to use .fetch or .get to actually retrieve results from the GqlQuery that you created, but for the first version, where you have a key or an id, you don't want to create a query at all. Rather, use the methods that are provided for using them directly.
If you have an id, use:
my_post = Post.get_by_id(id)
this will be much faster than using a query object.
If you have an entire key, use:
my_post = Post.get(key)
That is the fastest and most efficient way to get an entity out of the database.

Getting error message (if value is not None and not value.has_key() )

I am trying to save Event. But it does not work. Will you please help? thanks alot
query = []
query = Identity.all().filter('name =', 'k').fetch(1)
if query:
for q in query:
event_id = q.key().id()
Event(description=description, identity=event_id)
Event Model
class Event(search.SearchableModel):
description = db.TextProperty(required=True)
identity = db.ReferenceProperty(Identity)
Getting error message >
if value is not None and not value.has_key():
AttributeError: 'long' object has no attribute 'has_key'
Your assigning the id of the object into a ReferenceProeprty, this is wrong.
Your code should look something like this:
query = Identity.all().filter('name =', 'k').get()
if query:
Event(description=description, identity=q)
Also instead of having your own name attribute you use use the buitin key_name attribute that each Model has, its faster and cheaper.
query = Identity.get_by_key_name(k)
if query:
Event(description=description, identity=q)

Resources