How to customize the update functionality in ColdFusion ORM? - orm

I want to customize the update function of ORM. By default, ORM loads the object that needs to be updated, makes updates, and then saves the object. I want to update a record when a certain condition is satisfied.
For example :
I want to update payment mode from credit card to cash. Before updating records I want to check that I already have a cash payment mode. If one exists then I do not need to update a record otherwise update the record.
For the above checking I have used this SQL:
SELECT COUNT(*)
FROM hr_lookup_paymentmode
WHERE PaymentMode = 'cash'
AND modeid <> '10'
Equivalent HQL:
/**
* #hint Determines total number of results with same value of search for update purposes.
*/
remote numeric function searchUpdateCount(string q,numeric modeid ) output="false" {
var hqlString = "";
var whereClause = "";
var params = {};
hqlString = hqlString & "SELECT count(*) ";
hqlString = hqlString & "FROM hr_lookup_paymentmode";
if (len(arguments.q) gt 0)
{
whereClause = ListAppend(whereClause, " PaymentMode = '#arguments.q#'", "|");
whereClause = ListAppend(whereClause, "modeid <> '#arguments.modeid#'", "|");
whereClause = Replace(whereClause, "|", " AND ", "all");
}
if (len(whereClause) gt 0){
hqlString = hqlString & " WHERE " & whereClause;
}
return ormExecuteQuery(hqlString, false, params)[1];
}
Parameter q = 'cash' and modeid = 10. If count found is greater than 0 means record already exists, otherwise go for update.
Please help me apply this logic.

You can use ORM event handlers - either globally defined or defined in specific ORM objects. Here is some information on event handlers, but basically you would do the following in your ORM object:
function preUpdate( obj, data ){
{do stuff here }
}
In this example obj is the ORM entity you are trying to save and data is a structure containing the old data from the ORM entity. You would simply add your logic to the body of the function.

Related

Unable to locate appropriate constructor on class [ClassName]

I want to send a sql query by using Spring JPA like :
"SELECT NEW com.blalba.model.service.FamilyMaterialDto "
+ "(ms.id, mi.partNumber, ftc.commodityType, ftc.materialType, ms.grade, ms.thickness, ms.width) "
+ "FROM MaterialInstance mi, FamilyTypeCommodity ftc, MaterialSpecification ms "
+ "WHERE ftc.materialFamily.id = :familyId "
+ "AND (:typeId is null OR ftc.materialType.id = :typeId) "
+ "AND ftc.id = ms.familyTypeCommodity.id "
+ "AND ms.id = mi.materialSpecification.id "
+ "AND mi.materialSpecification.isActive = true"
However, when I remove some fields like "ms.width", I get the error:
Unable to locate appropriate constructor on class [com.commencis.sova.model.service.FamilyMaterialDto]. Expected arguments are: java.lang.String, java.lang.String, com.commencis.sova.model.entity.material.CommodityType, com.commencis.sova.model.entity.material.MaterialType, com.commencis.sova.model.entity.material.Grade, com.commencis.sova.model.entity.material.Thickness [SELECT NEW com.commencis.sova.model.service.FamilyMaterialDto (ms.id, mi.partNumber, ftc.commodityType, ftc.materialType, ms.grade, ms.thickness) FROM com.commencis.sova.model.entity.material.MaterialSpecification ms, com.commencis.sova.model.entity.material.MaterialInstance mi, com.commencis.sova.model.entity.material.FamilyTypeCommodity ftc WHERE ftc.materialFamily.id = :familyId AND (:typeId is null OR ftc.materialType.id = :typeId) AND mi.materialSpecification.isActive = true AND ms.id = mi.materialSpecification.id AND ftc.id = ms.familyTypeCommodity.id]
I understand that return Object[] cannot be parsed to DTO object. If I write constructor without the parameter - "Width", it will work properly. However, I want to provide that a query can be sendable without some parameters(sometimes one of them, sometimes five of them) and a result can be parsable with FamilyMaterialDTO.
How can I do? I don't have to use DTO, if there is another solution for this problem, please recommend.
I think you can make the query to return a map and you can create a constructor for FamilyMaterialDTO which takes the argument as a map. And based on the keys present in the map you can set the values...
For simplicity let me create my own class.
Class foo { String a; Integer b; Boolean c;}
And a sample query
"select new map (a as a, b as b) from Foo f"
Now this query will return a list of maps and the size of the list depends on how many rows the query returns.
Now you can create a constructor like this. Assume the size of list is 1.
foo (List<Map<?,?> list) {
Map map = list.get(0);
If(map.containsKey("a")) this.a = map.get("a");
If(map.containsKey("b")) this.b = map.get("b");
If(map.containsKey("c")) this.c = map.get("c"); }

multiple search in domino documents

In the onclick event of a button , I would like to search for a notes document , with multiple conditions with ssjs.
I have a form with a few fields. Now I would like to find a notes document where field a="123" and field b="456" field c="789" and field d >"A123456" , and then I would like to read the contents of field e.
If it was the search in a view I would use something like :
var tmpArray = new Array("");
var cTerms = 0;
if(viewScope.fong != null & viewScope.fong != "") {
tmpArray[cTerms++] = "(FIELD Site = \"" + viewScope.fong + "\")"
}
if(#Text(viewScope.sDate) != null & #Text(viewScope.sDate) != "") {
tmpArray[cTerms++] = "(FIELD StartDate = \"" + #Text(viewScope.sDate) + "\")"
}
qstring = tmpArray.join(" AND ").trim();
viewScope.queryString = qstring;
return qstring
If I only had 1 condition I would have used #DbLookup (and still how select documents >"A123456"?)
What's the best way of dooing this in ssjs ?
UPDATE
tried with FTSearch , but it seems in the searchkey "FIELD d > A123456" , doesn't seem to work
OTHER UPDATE
var dc = db.FTSearch("FIELD a=123 and FIELD b =456 and FIELD d =A123456");
seems to work but
var dc = db.FTSearch("FIELD a=123 and FIELD b =456 and FIELD d >A123456"); doesn't. It gives error : Exception occurred calling method NotesDatabase.FTSearch(string) null
If you want to use comparison operators > and <, then you need to use the NotesDatabase.Search method instead of FTSearch. Search is slower and can't access data in non-summary (i.e., rich text) fields, but it has all the same capabilities that you can use in a view selection formula.

How to build SELECT * WHERE using collection of conditions

I want to build a SELECT statement using a list of conditions that come from the query string of a REST api. I wrote this function, but maybe it is vulnerable to SQL injection. Can someone tell me if this is vulnerable how to fix it? Perhaps I should use some kind of SQLBuilder package? or is there a way to do it with just dotNet. I'm using dotNet 4.6.1
string BuildSelect(NameValueCollection query)
{
var result = "SELECT * FROM MYTABLE";
if (query.Count == 0) return result;
var logic = " WHERE ";
foreach (string key in query)
foreach (string v in query.GetValues(key))
{
result += logic + key + " = " + v;
logic = " AND ";
}
return result;
}
Yes it is vulnerable to SQL injection attack. You could build your query to use parameters instead (you are simply using an = check only).
Since you know the tablename, that means you also know what the columns (keys) can be. Thus, you could loop your columns, if the collection has that key then add it to the where as a parameterized statement BUT value part is NOT passed as a string, you parse it to the type it should be (or let the backend do the conversion and get error if cannot be converted). In pseudocode:
List<string> clauses = new List<string>();
var result = "SELECT * FROM MYTABLE";
foreach( var col in myTable.Columns )
{
if (query.ContainsKey(col.Name))
{
clauses.Add( $"{col.Name} = #{col.Name}";
string v = query[col.Name];
command.Parameters.Add( $"#{col.Name}", col.Type).Value = typeParse(v);
}
}
if (clauses.Any())
{
result += " WHERE " + string.Join( " AND ", clauses );
}
return result;
HTH

DataContext.ExecuteQuery<object> returns object {}

I'm trying to write function for selecting optional columns in linq(columns that may not exist). The problem is in linq like this:
using (DataDataContext db = new DataDataContext()){
var collection = from t in table
select new
{
Nonoptional = t.A;
Optional = IsInDB("table","B") ? t.B : -1; //this is optional column
}}
Unfortunately, this won't work because the fragment near Optional will be translated to case statement and error arises that column not exists.
So i decided to "cover" it with function:
using (DataDataContext db = new DataDataContext()){
var collection = from t in table
select new
{
Nonoptional = t.A;
Optional = IsInDB("table","B") ? OptionalColumnValue<int>("table","B","id_table",t.id_table) : -1; //this is optional column
}}
I want this function to be universal. It should work like that" If there is no value or column is nullable and value is null then return default value for type.
I came up with something like this:
//table,column - obvious,id_column - PK column of table, id - id of currently processing record
public static T OptionalColumnValue<T>(string table,string column,string id_columm,int id) T t = default(T);
DataDataContext db = new DataDataContext();
IEnumerable<object> value = db.ExecuteQuery<object>("select " + column + " from " + table + " where " + id_columm + " = " + id.ToString());
List<object> valueList = value.ToList();
if (valueList.Count == 1)//here is the problem
t = (T)valueList.First();
return t;
}
When there is null value db.ExecuteQuery return something like object{}. I'm assuming this is "empty" object,with nothing really in there. I was thinking about checking for "emptiness" of this object( BTW this is not DBull).
When i realised that this is no way either with concrete value in this column(it cannot cast it to return correct type), then I tried db.ExecuteQuery<T>. Then concrete value - OK, null - Exception.
I thought, maybe Nullable<T> as return value. Nop, because string also can be T.
I don't know what to do next. Maybe there's another solution to this problem.

CodeIgniter: Problem with variable sent to model

I'm inheriting someone else's project and I am trying to familiarize myself with it. I have little experience with CI.
On one of the views there's is a drop down form, on change calls a JS function:
$(document).ready(function()
{
// admin contorller drop down ajax
$("#catagoryDropDownList").change(function()
{
getCatagoriesItems();
});
// initiate table sort
TableSorter.prepareTable($("#dataResultsTable"));
});
// ajax request triggered by catagory drop down menu selection
function getCatagoriesItems()
{
blockPage();
// get base url of current site
var baseurl = $("#site_url_for_ajax").val();
// get adminType
var adminType = $("#admin_type").val();
// get catagory id
var catId = $("#catagoryDropDownList option:selected").attr("id");
var queryString = baseurl + "home/ajaxCatagorySelection/" + catId + "/" + adminType;
$.get(queryString, function(data)
{
var obj = jQuery.parseJSON(data);
// dump data into table when request is successful
$("#dataResultsTable tbody").html(JSONParser.parseHomeDropDownSelectedJSON(obj));
// unblock page when done
$.unblockUI();
});
}
I've logged the two values, catID and adminType, they're both integers, catID will be between 1-10 and adminType = 1. There both references to int values in a database. catID is referencing a field titled 'categoryID'. catID 6 = all. None of the entries in the db have 6 as their value, thus ensuring if you filtered for not equaling 6 you'd get all. They get passed to a function called ajaxCatagorySelection in the controller file home.php. So far, so good. Here's that function:
public function ajaxCatagorySelection($tableName, $id)
{
$vars = new DatabaseRetriever($id);
$resultsArray = $vars->getDataForSpecifiedTable($tableName, $id);
echo json_encode($resultsArray);
}
and that function itself is referencing a model (database_retriever.php) and the class DatabaseRetriever and I'm assuming passing the variables along to the function getDataForSpecifiedTable. I say assuming because the variable names have changed significantly from catID to $tableName and adminType to $id. Here is getDataForSpecifiedTable:
public function getDataForSpecifiedTable($catagoryInfo, $databaseID)
{
// connect to database
$sql = $this->connect($databaseID);
if ($catagoryInfo != 6) {
// build SQL Query and query the database
$result = $sql->query("SELECT fileId, fileTitle, filePath, fileTypeExt, fileDescription, fileModed from admin_files where catagoryId = '" . $catagoryInfo . "' and adminId = '" . $databaseID . "'");
} else {
$result = $sql->query("SELECT fileId, fileTitle, filePath, fileTypeExt, fileDescription, fileModed from admin_files where catagoryId = '" . $catagoryInfo . "' and adminId = '" . $databaseID . "'");
}
// declare array
$items = array();
// retriever rows from database and build array
while ($row = $result->fetch_row())
{
array_push($items, $row);
}
// disconnect from database
$this->disconnect();
// return data in array
return $items;
}
the variable names have changed again but you can tell they are suppose to do what I wrote above by looking at the query. Here's the problem. I added the conditional "if ($catagoryInfo != 6)...", if I don't put the else in there then CI throws out warning errors that no data is being returned. I return $categoryInfo and in the FireBug console I get the correct integer. I've tried the conditional as an integer and a string with both failing. Any ideas what might be happening here?
If database_retriever.php is a model, you should call it like so:
$this->load->model('database_retriever');
$resultsArray = $this->Database_retriever->getDataForSpecifiedTable($tableName, $id);
Also, make sure your model extends Model (or extends CI_Model in CodeIgniter 2).
NOTE: $.getJSON, will auto-parse JSON for you, so you don't need to call parseJSON.