Call stored procedure with optional parameters using OrmLite - servicestack

I am using OrmLite to call stored procedure that has optional parameters.
_dbConnection.SqlList<CustomerDTO>("sp_getcustomers #name", new { name = request.Name });
This statement is generating dynamic sql statement with #name as parameter. But I am not knowing how to pass null to this parameter, I tried using DBNull.Value but its not working.
Exception : The given key was not present in the dictionary is raised.
_dbConnection.SqlList<CustomerDTO>("sp_getcustomers #name", new { name = request.Name ?? System.Data.SqlTypes.SqlString.Null});

See these SqlProviderTests for examples of how to effectively make use of OrmLite's Sql* apis.
The right way to call it is with something like:
Db.SqlList<CustomerDTO>("EXEC sp_getcustomers #Name", new { request.Name });

Ormlite has a T4 file to generate C# functions equivalents for the SPs (for SqlServer); the generated files allows you to pass null values.

Support for null parameters in stored procedures was added in commit e6ef83a and released with version 3.9.56 of ServiceStack.OrmLite.

Related

Alias of an object key using COSMOSDB sql query

I am working with Cosmos DB and I want to write a SQL query that returns different name of an key in document object.
To elaborate, imagine you have the following document in one container having "makeName" key in "make" object.
{
"vehicleDetailId":"38CBEAF7-5858-4EED-8978-E220D2BA745E",
"type":"Vehicle",
"vehicleDetail":{
"make":{
"Id":"B57ADAAD-C16E-44F9-A05B-AAB3BF7068B9",
"makeName":"BMW"
}
}
}
I want to write a query to display "vehicleMake" key in place of "makeName".
How to give alias name in the nested object property.
Output should be like below
{
"vehicleDetailId":"38CBEAF7-5858-4EED-8978-E220D2BA745E",
"type":"Vehicle",
"vehicleDetail":{
"make":{
"Id":"B57ADAAD-C16E-44F9-A05B-AAB3BF7068B9",
"vehicleMake":"BMW"
}
}
}
I have no idea how to query in Cosmosdb to get the above result.
Aliases for properties are similar to the way you'd create a column alias in SQL Server, with the as keyword. In your example, it would be:
SELECT c.vehicleDetail.make.makeName as vehicleMake
FROM c
This would return:
[
{
"vehicleMake": "BMW"
}
]
Try this:
SELECT c.vehicleDetailId, c.type,
{"make":{"Id":c.vehicleDetail.make.Id, "vehicleMake":c.vehicleDetail.make.makeName}} as vehicleDetail
FROM c
It uses the aliasing described in the following documentation. All of the aliasing examples I could find in the documentation or blog posts only show a single level of json output, but it happens that you can nest an object (make) within an object (vehichleDetail) to get the behavior you want.
https://learn.microsoft.com/en-us/azure/cosmos-db/sql-query-aliasing

In Microsoft Bot Framework session.conversationData.array of regexes changes to array of Object type after executing once

I am working with the below piece of code in Microsoft Bot Framework to access the list of regexes for global commands. This code is a part of botbuilder module:
if (typeof session.conversationData.globalCommands === "undefined") {
// An array which contains the list of all global commands
session.conversationData.globalCommands = [];
// Accessing the list of global commands
globalActions = session.library.actions.actions;
lenGlobalActions = Object.keys(globalActions).length;
// Assigning values to the above list
for (var i=0; i<lenGlobalActions; i++){
session.conversationData.globalCommands.push(globalActions[Object.keys(globalActions)[i]].options.matches);
}
}
// Checking if the incoming message from the user is a global command
var isGlobalCommand = session.conversationData.globalCommands.some(regex => regex.test(session.message.text));
The issue here is, the code runs fine for the first time and the values assigned to the variable session.conversationData.globalCommands are in the form given below:
However, after the first execution, the array converts to the below without any changes made in the code anywhere else:
Due to this, the line:
var isGlobalCommand = session.conversationData.globalCommands.some(regex => regex.test(session.message.text));
throws an exception "regex.test is not a function".
I am unable to understand why this should be happening and how do I solve this as I need this list separately for some processing.
I believe you cannot store complex types in the bot store (conversationData, etc). The object needs to be serializable to JSON and I don't believe a RegExp it is.
The workaround would be to store the regex as an string and then recreate the regex object using the constructor and the stored string expression.
Check the core-State sample to know more about the store capabilities.

Different variable name case convention in one application

This is a really trivial problem. I am just curious on how to deal with this in a "professional" manner.
I am trying to stick to variable naming convention. For NodeJs I am doing camelCasing. For database, I am using PostgreSQL and using underscore_casing.
Now the problem arises when I query data from PostgreSQL. I'll get a user object with following format,
{user_id: 1, account_type : "Admin"}
I can pass this object directly to server side-render and will have to use underscore casing to access account_type. Of course, I can manually create a new user JSON object with property userId and accountType but that is unnecessary work.
Is it possible to follow variable naming convention for both language and avoid having mixed variable names casing in some files? What is a good way to stay organized?
The are two good ways to approach this issue. The simplest one - do no conversion, use the exact database names. And the second one is to camel-case columns automatically.
Either way, you should always follow the underscore notation for all PostgreSQL declarations, as it will give you the option to activate camel-casing in your app at a later time, if it becomes necessary. Never use camel-case inside the database, or you will end up in a lot of pain later.
If you want the best of both worlds, follow the underscore notation for all PostgreSQL declarations, and convert to camel-case as you read data.
Below is an example of how to do it properly with pg-promise, copied from event receive example:
// Example below shows the fastest way to camelize column names:
const options = {
receive(e) {
camelizeColumns(e.data);
}
};
function camelizeColumns(data) {
const template = data[0];
for (var prop in template) {
const camel = pgp.utils.camelize(prop);
if (!(camel in template)) {
for (var i = 0; i < data.length; i++) {
const d = data[i];
d[camel] = d[prop];
delete d[prop];
}
}
}
}
Also see the following article: Pg-promise and case sensitivity in column names.
UPDATE
The code above has been updated for use of pg-promise v11 or later.
I've struggled with this too, and I've concluded that there's really no way to avoid this kind of ugliness unless you rewrite the objects that come from the database. Fortunately, that's not too difficult in Javascript:
const fromDBtoJS = (obj) => {
// declare a variable to hold the result
const result = {};
// iterate over the keys on the object
Object.keys(obj).forEach((key) => {
// adjust the key
const newKey = key.replace(/_[a-z]/g, (x) => x[1].toUpperCase());
// add the value from the old object with the new key
result[newKey] = obj[key];
});
// return the result
return result;
};
Here's a JSFiddle. The "replace" code above was found here
If you wanted to use classes for models in your application, you could incorporate this code into the constructor or database load method so it's all handled more-or-less automatically.

How to Execute an Existing Stored Procedure in DocumentDB?

I want to create a stored procedure in DocumentDB and use it whenever I need later on. To execute a stored procedure I need to know a storedProcedureLink. When I register stored procedure with CreateStoredProcedureAsync method I get the link, am I supposed to store this link somewhere myself if I want to execute this stored procedure later? Can I execute a stored procedure if all I know is a procedure name? From all the examples I found it seems that I need to create and register stored procedure right before I need to execute it, is it the case?
You can absolutely create the Stored Procedure beforehand and have it saved on the server for future use. You do not need to create it just before using it. This was for sample purposes only. We expect the majority of the time that the stored procedures will exist already and you just use them in your application.
You do need the SelfLink to execute the Stored Procedure.
One way to get this would be to query for the Stored Procedure (by Name), get the SelfLink and then use that to execute the stored procedure.
Querying for a Stored Procedure by name would look something like;
StoredProcedure sproc = client.CreateStoredProcedureQuery(collection.StoredProceduresLink, "select * from root r where r.id = \"sproc name\"");
The resulting sproc variable will contain the SelfLink of the stored procedure you want to execute.
var result = client.ExecuteStoredProcedureAsync(sproc.SelfLink);
For comprehensive samples of how to work with Stored Procedures please see the DocumentDB.Samples.ServerSideScripts project in the samples posted at;
http://code.msdn.microsoft.com/Azure-DocumentDB-NET-Code-6b3da8af
From all the examples I found it seems that I need to create and register stored procedure right before I need to execute it, is it the case?
No. Stored procedure creation and registration does not have to happen during execution.
The samples are educational, but do not offer real-world patterns. See the DocumentManagement basic CRUD operations. Samples also assume a single collection too. See the Partitioning basic CRUD operations.
While I applaud the DocumentDB adaption of SQL coding conventions, the usage pattern currently falls short for .NET developers. The decade old pattern of creating CRUD stored procedures in SQL Server and then calling them by name via ADO.NET or a TableAdapter in a DataSet does not work in the DocumentDB.
Can I execute a stored procedure if all I know is a procedure name?
Yes, but it's not pretty:
StoredProcedure storedProcedure = this.DocumentClient.CreateStoredProcedureQuery(new Uri(collection.StoredProceduresLink)).Where(p => p.Id == "GetPunkRocker").AsEnumerable().FirstOrDefault();
When using a PartitionResolver, things get more complicated:
public async Task<PunkRocker> GetPunkRockerAsync(string partitionKey)
{
foreach (string collectionLink in this.PartitionResolver.ResolveForRead(partitionKey))
{
DocumentCollection collection = this.DocumentClient.CreateDocumentCollectionQuery(new Uri(this.Database.SelfLink)).Where(c => c.SelfLink == collectionLink).AsEnumerable().FirstOrDefault();
if (collection == null)
{
// Log...
continue;
}
StoredProcedure storedProcedure = this.DocumentClient.CreateStoredProcedureQuery(new Uri(collection.StoredProceduresLink)).Where(p => p.Id == "GetPunkRocker").AsEnumerable().FirstOrDefault();
if (storedProcedure == null)
{
// Log...
continue;
}
PunkRocker punkRocker = await this.DocumentClient.ExecuteStoredProcedureAsync<PunkRocker>(new Uri(storedProcedure.SelfLink), partitionKey);
if (punkRocker != null)
{
return punkRocker;
}
}
return null;
}
Just tried this approach and it does not work.
client.CreateStoredProcedureQuery( link, String.Format( "select * from root r where r.id = '{0}'", "spname1" ) ).ToList( ).FirstOrDefault( );
returns null
client.CreateStoredProcedureQuery( link, String.Format( "select * from root r" ) ).ToList( ).FirstOrDefault( );
returns correct stored procedure
{
"id": "spname1",
"body": "function() {
var context = getContext();
var collection = context.getCollection();
}",
"_rid": "XXX",
"_ts": 1410449011.0,
"_self": "XXX",
"_etag": "XXX"
}
You can look for the SP in the DB first in .NET SDK
StoredProcedure storedProcedure = Client.CreateStoredProcedureQuery(GetCollection(eColl).SelfLink).Where(c => c.Id == "SP name").AsEnumerable().FirstOrDefault();
It appears that Microsoft is now providing a few samples on how to execute stored procedures:
https://learn.microsoft.com/en-us/dotnet/api/microsoft.azure.documents.client.documentclient.executestoredprocedureasync?view=azure-dotnet

Docuemt postopen event not operating on profile document

I need to save serial number of the document in a profile document and here is a code of action Execute Script:
if (document1.isNewNote()){
var pdoc:NotesDocument=database.getProfileDocument("LastNumber","")
var lnm=pdoc.getItemValue("lastNumber")[0];
var inputText6:com.ibm.xsp.component.xp.XspInputText = getComponent("inputText6");
inputText6.setValue(lnm);
pdoc.replaceItemValue("lastNumber",lnm);
pdoc.save();
}
This code is not opening profile document at all. Any thing wrong in the code?
"LastNumber" is the name of the form used to create Profile Document ?
this profile document already exist ?
there are no reader fields in this profile document ?
you have an error on this line : var pdoc:NotesDocument=database.getProfileDocument("LastNumber","") ?
or you have debug it and see that pdoc is null ?
instead of pdoc.getItemValue("lastNumber")[0] you can use pdoc.getItemValueInteger("lastNumber") to get a typed result
I supposed that this field contains a number and you want to increment it
instead of using inputText field you can set value directly with document1.setValue("NumberField", lnm);
I second the caution Per is suggesting. Profile documents can be a beast. You should abstract access to the "next number" into a SSJS function call. Btw. in your code snippet you don't actually increment the last number. Also: if your input text control is bound, go after the data source, not the UI.
A crude way (I would use a managed application bean for better isolation) for a better function could be this:
if(document1.isNewNote() {
document1.setValue("DocumentNumber",applicationTools.getNextNumber());
}
Then in a SSJS library you would have:
var applicationTools = {
"getNextNumber" : function() {
synchronized(applicationScope){
var pdoc:NotesDocument=database.getProfileDocument("LastNumber","");
if (!applicationScope.lastNumber) {
applicationScope.lastNumber = pdoc.getItemValueInteger("lastNumber");
}
applicationScope.lastNumber++;
pdoc.replaceItemValue("lastNumber",applicationScope.lastNumber);
pdoc.save(); //Make sure pdoc is writeable by ALL!!!!
pdoc.recycle();
return applicationScope.lastNumber;
}
},
"someOtherUtility" : function(nameToLookup, departments) {
// more stuff here
}
}
Which, in some way has been asked before, but not for a profile field. Someone still could simply go after the applicationScope.lastNumber variable, which is one of the reasons why I rather use a bean. The other: you could do the saving asynchronously, so it would be faster.
Note: in any case the number generation only works when you have a non-replicating database. But abstracting the function opens the possibility to replace fetching the number from the profile with a call to a central number generator ... or any other mechanism ... without changing your form again.

Resources