how to retrieve multiple properties using #NameLookup in lotus notes - lotus-notes

I am using #NameLookUp formula to retrieve internet address by giving a search key and it is working fine.But now i want to retrive not only the internet address but also some other properties like FirstName and LastName.
Here is the formula i am using to #Namelookup internet address by giving search string.
Vector vec=m_session.evaluate("#NameLookup([NoUpdate];\""+ userName + "\"; \"InternetAddress\")");
//username is the String variable(Search Criteria)
Can anyone please help how to retrieve multiple properties(like firstName and lastName along with InternetAddress) by evaluate the formula only once. If it cant be done using #Namelookup is there any other way..?

This is a typical example when using evaluate() to call a Formula is not a good idea.
What you want to do is to get the NotesDocument class and read values from it.
Something like this (disclaimer, I am not a Java developer):
// Open Domino Directory on specified server
Database db = session.getDatabase("YourServer/Domain", "names.nsf");
// Get a view with user name is sorted first column
View view = db.getView("($Users)");
// Get the person document for specified user
Document doc = view.getDocumentByKey(userName, true);
if (doc != null) {
// Get text values from Notes document
String emailAddress = doc.getItemValueString("InternetAddress");
String officePhone = doc.getItemValueString("OfficeNumber");
String officeAddress = doc.getItemValueString("OfficeStreetAddress");
}
I believe this would be faster than multiple lookups using evaluate(), and you also have the added benefit of full error handling, and all being native code.

#NameLookup only returns the value of one item per call.
Assuming your goal is to only have one Evaluate statement, you could chain the calls together and return an array of values in a certain order:
Vector vec=m_session.evaluate("FirstName := #NameLookup([NoUpdate];\""+ userName + "\"; \"FirstName\"); LastName:= #NameLookup([NoUpdate];\""+ userName + "\"; \"LastName\"); InternetAddress :=#NameLookup([NoUpdate];\""+ userName + "\"; \"InternetAddress\"); FirstName:LastName:InternetAddress");
Or possibly:
String firstName = m_session.evaluate("#NameLookup([NoUpdate];\""+ userName + "\"; \"FirstName\")");
String lastName = m_session.evaluate("#NameLookup([NoUpdate];\""+ userName + "\"; \"LastName\")");
String internetAddress = m_session.evaluate("#NameLookup([NoUpdate];\""+ userName + "\"; \"InternetAddress\")");
And then add those three strings in any order into your Vector.

Another approach is to use the DirectoryNavigator class. I believe it's been available since Notes/Domino 8.5 (perhaps even before that). DirectoryNavigator uses some of the same core logic as #NameLookup, so it should perform well.
Here's some sample code. I haven't tested this exact code, but I adapted it from production code that does a similar lookup:
String firstName = null;
String lastName = null;
String inetAddress = null;
Vector<String> lookupItems = new Vector<String>();
lookupItems.addElement("FirstName");
lookupItems.addElement("LastName");
lookupItems.addElement("InternetAddress");
Vector<String> vName = new Vector<String>();
vName.addElement(userName);
Directory dir = session.getDirectory();
DirectoryNavigator dirNav = dir.lookupNames("($Users)", vName, lookupItems, true);
if( dirNav != null && dirNav.getCurrentMatches() != 0 ) {
// Digest the results of the lookup
Vector<String> value = null;
value = dirNav.getFirstItemValue();
firstName = value.elementAt(0);
value = dirNav.getNextItemValue();
lastName = value.elementAt(0);
value = dirNav.getNextItemValue();
inetAddress = value.elementAt(0);
}

Related

Custom LIKE statement in Java Spring Data and Cassandra #Query

I need to query from a table using LIKE statement where parameters are optional.
This is custom query where I can filter employee table by which Non-Empty request param:
Select select = QueryBuilder.select().from("employee");
Where selectWhere = select.where();
if (!email.isEmpty()) {
selectWhere.and(QueryBuilder.like("email", "%" + email + "%"));
}
if (!firstName.isEmpty()) {
selectWhere.and(QueryBuilder.like("first_name", "%" + firstName + "%"));
}
//Note: User will provide either email or first_name or both.
However, the above custom query will need to manually map the Rows to the object which I find too tedious:
ResultSet rs = cassandraClient.getApplicationSession().execute( select );
return rs.all().stream().map(row -> row.getString("first_name")).collect( Collectors.toList() );
Is there a way where I can use a Query annotation like below, so it will return the entity directly?
#Query("SELECT * FROM employee WHERE email LIKE :email AND first_name LIKE :firstName")
Employee search(#Param(value="email" String email, #Param(value="firstName" String firstName)
I tried passing an empty parameter value, but I am getting the following error:
LIKE value can't be empty.

Getting Active View Object Parameters?

I am new to the API and I'm trying to get values from the active view. I am using the following code as a mock up to what I'm trying to do:
public void GetViewProperties()
{
String viewname;
String typename;
String levelname;
String Output;
ViewFamilyType VfamType;
Level lev;
//Get document and current view
Document doc = this.ActiveUIDocument.Document;
View currentView = this.ActiveUIDocument.ActiveView;
//Find the view family type that matches the active view
VfamType = new FilteredElementCollector(doc).OfClass(typeof(ViewFamilyType))
.Where(q => q.Name == "1-0-Model").First() as ViewFamilyType;
//Find the level that matches the active view
lev = new FilteredElementCollector(doc).OfClass(typeof(Level))
.Where(q => q.Name == "00").First() as Level;
//Get the view's current name
viewname = currentView.Name.ToString();
//Get the name of the view family type
typename = VfamType.Name;
//Get the name of the level
levelname = lev.Name.ToString();
//Combine results for task dialog
Output = "View: " + viewname + "\n" + typename + "-" + levelname;
//Show results
TaskDialog.Show("View Properties Test",Output);
}
I'm cheating at the moment by grabbing the view type and level by name. I really want them to be found by looking at the properties of the active view. I can't figure out how I am meant to access the view type and level name properties. I need to make lambda use a variable e.g. (q => q.Name == Level.name), (q => q.Name == ViewFamilyType.name).
Thanks in advance!
Here is your code corrected:
public void GetViewProperties()
{
//Get document and current view
Document doc = this.ActiveUIDocument.Document;
View currentView = this.ActiveUIDocument.ActiveView;
//Find the view family type that matches the active view
var VfamType = (ViewFamilyType)doc.GetElement(currentView.GetTypeId());
//Find the level that matches the active view
Level lev = currentView.GenLevel;
//Get the view's current name
string viewname = currentView.Name;
//Get the name of the view family type
string typename = VfamType.Name;
//Get the name of the level
string levelname = lev.Name;
//Combine results for task dialog
string Output = "View: " + viewname + "\n" + typename + "-" + levelname;
//Show results
TaskDialog.Show("View Properties Test", Output);
}
You don't need to use a FilteredElementCollector to get these informations. And if you need elsewhere, you don't need a Where: just put your lambda in the First:
new FilteredElementCollector(doc).OfClass(typeof(ViewFamilyType))
.First(q => q.Name == "1-0-Model")
If you need to access in your lambda a property specific to a class, not defined on Element, you can use Cast:
new FilteredElementCollector(doc).OfClass(typeof(ViewFamilyType))
.Cast<ViewFamilyType>().First(vft => vft.IsValidDefaultTemplate)
And please do not declare all your variable at the start of your methods. You're not writing Pascal. Declare variables as close to the first spot that you use them as possible. It makes your code much more readable. The closer a variable is declared to where it is used, the less scrolling/searching you have to do when reading the code later and it also naturally narrow their scope.
You're probably looking for View.GenLevel property. This will work for views related to levels, such as Plan Views. Note that if this View is not generated by a level, this property is null.

mutivalue date field search not working

I have a multivalue field called freeDaysPool which has multiple dates as strings. With the following code, the search does not return anything. If I leave that field out, the search works just fine with the two other fields. I read that I should use CONTAINS with multivalue fields but then I got query not understandable.
I've tried the back-end field as a date field and as a text field and tested all kinds of query combinations and date formats but no luck. Any help is really appreciated.
This is the search button code:
var query = new Array("");
var cTerms = 0;
// Field 1
var search01 = getComponent("searchcustomReservationField01").getValue();
if (#Contains(#Text(search01),"any city")){"";}
else {query[cTerms++] = '[customReservationField01]="' + search01 +'"'};
// Field 2
var search02 = getComponent("searchcustomReservationField02").getValue();
if (#Contains(#Text(search02),"any city")){"";}
else {query[cTerms++] = '[customReservationField02]="' + search02 + '"'};
// Date 1
var formatter = new java.text.SimpleDateFormat("d.M.yyyy");
query[cTerms++] = 'FIELD freeDaysPool = ' + formatter.format(getComponent("searchcustomDateField01").getValue());
// if query is still empty, we fill it with asterisk
if(query == "" || query == null){
query[cTerms++] = "*";
}
// make all as string
qstring = query.join(" AND ").trim();
sessionScope.searchString = qstring;
It will return query as:
[customReservationField01]="Oslo" AND [customReservationField02]="Oslo" AND FIELD freeDaysPool = 6.2.2015
AFAIK date values in formulas (and a query is a formula) have to be noted like
[06.02.2015]
to compare them. Just try to use your formular in the Notes Client to do a fulltext search. If you get results and no errors you found the correct format. That's at least the way I test queries as I'm not able to remind the syntax for years :-D
Thank you for all the help! Seems that Domino keeps the field type as date field even if you change it back to text field (noticed that from the notes FTsearch). I created completely new text field and added the days as strings in dd.MM.yyyy format. I also search them as strings and it works fine.
The changed code bit now looks like this:
// Date 1
var formatter = new java.text.SimpleDateFormat("dd.MM.yyyy");
query[cTerms++] = '[freeDays] CONTAINS "' + formatter.format(getComponent("searchcustomDateField01").getValue())+'"';

Creating a case in plugin, want to use its ticketnumber immediately

I have a plugin where i am creating a new case and I want to send an email out as it is created including its ticketnumber. I have attempted just to call this in the plugin but it is coming back saying that it is not present in the dictionary. I know this field is populated using CRM's own autonumbering so what i'm guessing is happening is that my plugin is firing and creating the case but then i'm trying to use this field before the autonumber has completed.
So is there a way that i can get my plugin to "wait" until this field is available and then use it?
Thanks
EDIT: Code below:
string emailBody = entity.Attributes["description"].ToString();
int bodyLength = emailBody.Length;
int textStart = emailBody.IndexOf(">") + 1;
int newLength = bodyLength - (textStart + 7);
string description = emailBody.Substring(textStart, newLength);
//create complaint
Entity complaint = new Entity("incident");
complaint["description"] = description;
complaint["ts_case_type"] = 717750001;
complaint["ts_registration_datetime"] = DateTime.Now;
complaint["ownerid"] = Owner;
complaint["customerid"] = Organisation;
Service.Create(complaint);
As a side I would suggest sending the email with a workflow if possible, it will be far easier to maintain in the long run and quicker to implement in the short.
In any case to answer your question, from what you have here you need to update your code to retrieve the ticketnumber once you have created the incident. You can do this with a Retrieve message.
For example:
//Create the complaint
Entity complaint = new Entity("incident");
//This is the information that is being sent to the server,
//it will not be updated by CRM with any additional information post creation
complaint["description"] = description;
complaint["ts_case_type"] = 717750001;
complaint["ts_registration_datetime"] = DateTime.Now;
complaint["ownerid"] = Owner;
complaint["customerid"] = Organisation;
//Capture the id of the complaint, we will need this in a moment
Guid complaintId = Service.Create(complaint);
//complaint["ticketnumber"] <-- The server does not populate this information in your object
//Retrieve the ticketnumber from the incident we just created
Entity complaintRetrieved = service.Retrieve("incident", complaintId, new ColumnSet("ticketnumber"));
//Get the ticketnumber
String ticketNumber = (String)complaintRetrieved.Attributes["ticketnumber"];
Like James said in comment, if you just want to send email with some case properties, it is best to do that with workflow (on case create).
In your plugin, ID is generated, and you can get it with:
entity.Attributes["ticketnumber"]

Subsonic 3 - Sequence contains no matching element

I need help creating a LINQ SQL with subsonic. First the basics, this works fine:
var query = (from o in bd.concelhos
orderby o.descricao
select o);
var results = query.ToList<concelhos>();
However, I want to filter out some columns and I have created the following code:
var query = (from o in bd.concelhos
orderby o.descricao
select new FilteredConcelhos { id = o.idDistrito + "/" + o.idConcelho, descricao = o.descricao });
var results = query.ToList<FilteredConcelhos>();
which errors out in the ToList method with the description "Sequence contains no matching element"
Any help would be great with this...
update:
Turns out I was missing get set attributes in the newly declared class...
Like so
public class FilteredConcelhos
{
public string id { get; set; }
public string descricao { get; set; }
}
This clears the exception, but the resulting List is still all wrong (FilteredConcelhos.id contains nothing and FilteredConcelhos.descricao contains numbers)
Can you try to first execute the ToList and the select afterwards - then the select is performed via linq 2 objects!
Have you tried to work with an anonymous type?
var query = (from o in bd.concelhos
orderby o.descricao
select new { id = o.idDistrito + "/" + o.idConcelho,
descricao = o.descricao });
var results = query.ToList();
Unfortunately, this happened to me a lot. I'm not sure about the details of how Linq 2 Object works, but if you'll call ToList on the original object, like this:
from o in bd.concelhos.ToList()
...
It should do the trick.

Resources