ServiceStack Ormlite Deserialize Array for In Clause - service

I am storing some query criteria in the db via a ToJson() on the object that contains all the criteria. A simplified example would be:
{"FirstName" :[ {Operator: "=", Value: "John"}, { Operator: "in", Value:" ["Smith", "Jones"]"}], "SomeId": [Operator: "in", Value: "[1,2,3]" }]}
The lists are either string, int, decimal or date. These all map to the same class/table so it is easy via reflection to get FirstName or SomeId's type.
I'm trying to create a where clause based on this information:
if (critKey.Operator == "in")
{
wb.Values.Add(keySave + i, (object)ConvertList<Members>(key,
(string)critKey.Value));
wb.WhereClause = wb.WhereClause + " And {0} {1} (#{2})".Fmt(critKey.Column,
critKey.Operator, keySave + i);
}
else
{
wb.Values.Add(keySave + i, (object)critKey.Value);
wb.WhereClause = wb.WhereClause + " And {0} {1} #{2}".Fmt(critKey.Column, critKey.Operator, keySave + i);
}
It generates something like this (example from my tests, yes I know the storenumber part is stupid):
Email = #Email0 And StoreNumber = #StoreNumber0 And StoreNumber in (#StoreNumber1)
I'm running into an issue with the lists. Is there a nice way to do this with any of the ormlite tools instead of doing this all by hand? The where clause generates fine except when dealing with lists. I'm trying to make it generic but having a hard time on that part.
Second question maybe related but I can't seem to find how to use parameters with in. Coming from NPoco you can do (colum in #0, somearray)` but I cant' seem to find out how to do this without using Sql.In.

I ended up having to write my own parser as it seems ormlite doesn't support have the same support for query params for lists like NPoco. Basically I'd prefer to be able to do this:
Where("SomeId in #Ids") and pass in a parameter but ended up with this code:
listObject = ConvertListObject<Members>(key, (string)critKey.Value);
wb.WhereClause = wb.WhereClause + " And {0} {1} ({2})"
.Fmt(critKey.Column, critKey.Operator,listObject.EscapedList(ColumnType<Members>(key)));
public static string EscapedList(this List<object> val, Type t)
{
var escapedList = "";
if (t == typeof(int) || t == typeof(float) || t == typeof(decimal))
{
escapedList = String.Join(",", val.Select(x=>x.ToString()));
} else
{
escapedList = String.Join(",", val.Select(x=>"'" + x.ToString() + "'"));
}
return escapedList;
}
I'd like to see other answers especially if I'm missing something in ormlite.

When dealing with lists you can use the following example
var storeNumbers = new [] { "store1", "store2", "store3" };
var ev = Db.From<MyClass>
.Where(p => storeNumbers.Contains(p => p.StoreNumber));
var result = Db.Select(ev);

Related

Replace characters in foreach variable

Here is the code:
def readEntityMultipleTimes(entityName: String, pathPrefix: String = "") = {
val plural = entityName + "s"
exec(http(s"Geting all $plural")
.get(pathPrefix + plural)
.check(status is 200)
.check(jsonPath("$[*].id").findAll.saveAs("entityIds"))
).exec(s => {
if (logLevel >= 2) println("\nids:\n" + s("entityIds"))
s
})
.pause(interval millis)
.foreach("${entityIds}", "entityId") {
repeat(readEntityNumber) {
exec(http(s"Getting one $entityName")
.get(pathPrefix + plural + "/${entityId}")
.check(status is 200)
)
}
}
}
The issue is that entityId may contain a space and it fails the HTTP GET request. I need the spaces to be replaced with %20.
I tried the gatling EL ${entityId.replaceAll(\" \", \"%20\")}"
or ${java.net.URLEncoder.encode(entityId)}
I guess the suggested way is to get the entityId from the session and do the stuff in Scala, but this variable is dynamically created for each loop iteration, so I am not sure where to put the "session lambda" (session => ...)
Gatling EL syntax is limited and you can't place any Scala code in there.
You indeed have to pass a function.
.get(session => pathPrefix + plural + URLEncoder.encode(session("entityId").as[String])))

Entity Framework - Table-Valued Functions - Parameter Already Exists

I am using table-valued functions with Entity Framework 5. I just received this error:
A parameter named 'EffectiveDate' already exists in the parameter collection. Parameter names must be unique in the parameter collection. Parameter name: parameter
It is being caused by me joining the calls to table-valued functions taking the same parameter.
Is this a bug/limitation with EF? Is there a workaround? Right now I am auto-generating the code (.edmx file).
It would be really nice if Microsoft would make parameter names unique, at least on a per-context basis.
I've created an issue for this here.
In the meantime, I was able to get this to work by tweaking a few functions in the .Context.tt file, so that it adds a GUID to each parameter name at runtime:
private void WriteFunctionImport(TypeMapper typeMapper, CodeStringGenerator codeStringGenerator, EdmFunction edmFunction, string modelNamespace, bool includeMergeOption) {
if (typeMapper.IsComposable(edmFunction))
{
#>
[EdmFunction("<#=edmFunction.NamespaceName#>", "<#=edmFunction.Name#>")]
<#=codeStringGenerator.ComposableFunctionMethod(edmFunction, modelNamespace)#>
{ var guid = Guid.NewGuid().ToString("N"); <#+
codeStringGenerator.WriteFunctionParameters(edmFunction, " + guid", WriteFunctionParameter);
#>
<#=codeStringGenerator.ComposableCreateQuery(edmFunction, modelNamespace)#>
} <#+
}
else
{
#>
<#=codeStringGenerator.FunctionMethod(edmFunction, modelNamespace, includeMergeOption)#>
{ <#+
codeStringGenerator.WriteFunctionParameters(edmFunction, "", WriteFunctionParameter);
#>
<#=codeStringGenerator.ExecuteFunction(edmFunction, modelNamespace, includeMergeOption)#>
} <#+
if (typeMapper.GenerateMergeOptionFunction(edmFunction, includeMergeOption))
{
WriteFunctionImport(typeMapper, codeStringGenerator, edmFunction, modelNamespace, includeMergeOption: true);
}
} }
...
public void WriteFunctionParameters(EdmFunction edmFunction, string nameSuffix, Action<string, string, string, string> writeParameter)
{
var parameters = FunctionImportParameter.Create(edmFunction.Parameters, _code, _ef);
foreach (var parameter in parameters.Where(p => p.NeedsLocalVariable))
{
var isNotNull = parameter.IsNullableOfT ? parameter.FunctionParameterName + ".HasValue" : parameter.FunctionParameterName + " != null";
var notNullInit = "new ObjectParameter(\"" + parameter.EsqlParameterName + "\"" + nameSuffix + ", " + parameter.FunctionParameterName + ")";
var nullInit = "new ObjectParameter(\"" + parameter.EsqlParameterName + "\"" + nameSuffix + ", typeof(" + parameter.RawClrTypeName + "))";
writeParameter(parameter.LocalVariableName, isNotNull, notNullInit, nullInit);
}
}
...
public string ComposableCreateQuery(EdmFunction edmFunction, string modelNamespace)
{
var parameters = _typeMapper.GetParameters(edmFunction);
return string.Format(
CultureInfo.InvariantCulture,
"return ((IObjectContextAdapter)this).ObjectContext.CreateQuery<{0}>(\"[{1}].[{2}]({3})\"{4});",
_typeMapper.GetTypeName(_typeMapper.GetReturnType(edmFunction), modelNamespace),
edmFunction.NamespaceName,
edmFunction.Name,
string.Join(", ", parameters.Select(p => "#" + p.EsqlParameterName + "\" + guid + \"").ToArray()),
_code.StringBefore(", ", string.Join(", ", parameters.Select(p => p.ExecuteParameterName).ToArray())));
}
Not a bug. Maybe a limitation or an omission. Apparently this use case has never been taken into account. EF could use auto-created parameter names, but, yeah, it just doesn't.
You'll have to resort to calling one of the functions with .AsEnumerable(). For some reason, this must be the first function in the join (as I have experienced). If you call the second function with .AsEnumerable() it is still translated to SQL and the name collision still occurs.

How to write this Query in LINQ

I have one LINQ query with foreach loop. Everything is fine. But it takes more time to get the value. So anybody suggest me how can i do this in LINQ query itself.
Code
NormValue = "";
c = 0;
var NormValuelist = db.BCont.Where(x => x.BId == BId && x.TNo == Tag).ToList();
foreach (var item in NormValuelist)
{
if (c == 0)
NormValue = item.NormValue;
else
NormValue += " " + item.NormValue;
c = 1;
}
Thanks
You can rewrite this query with string.Join to avoid creating multiple string objects in a loop, like this:
string NormValue = string.Join(" ", db.BCont.Where(x => x.BId == BId && x.TNo == Tag));
The number of round-trips to DB will remain the same, but the creation of List<string> and the partially concatenated string objects will be optimized out.
In addition to using String.Join, you could also use Enumerable.Aggregate:
var NormValueList =
db.BCont.Where(x => x.Bid == BId && x.TNo == Tag)
.Select(x => x.NormValue)
.Aggregate((s, x) => s + " " + x);
If you are having large items in "NormValuelist" then it would be better to use StringBuilder instead of string(NormValue)

can i use custom lambda method in entity framework?

i have some methods like:
public static string ToOtherFormat (this string inp)
{
// some code to change inp
return inp;
}
and in my select i want to have code like this:
var DetailMembers = db.TB_Members
.Where(x=> x.FName == obj.ToOtherFormat())
.Select( x=> new { name = (x.FName.ToOtherFormat() + " " + x.LName) , x.ActCode });
i try and just have error. is it possible?
thanks!
i receive this error in simple convert to integer
LINQ to Entities does not recognize the method 'Int32 ToInt32(System.String)' method, and this method cannot be translated into a store expression.
with this code
.Where(x => x.MemberID == Convert.ToInt32(Hmemid.Hash_two_Decrypt())
Looks like you are querying against the database. Your current query will get translated into SQL query and since SQL doesn't recognize your function that is why you get error.
You may get the data from the tables using a query without that function and then later do the formatting on the result set.
i found it on use .AsEnumerable() method like:
var DetailMembers = db.TB_Members.AsEnumerable()
.Where(x=> x.FName == obj.ToOtherFormat())
.Select( x=> new { name = (x.FName.ToOtherFormat() + " " + x.LName) , x.ActCode });

Is there a way to auto expand objects in Chrome Dev Tools?

EVERY SINGLE TIME I view an object in the console I am going to want to expand it, so it gets tiresome to have to click the arrow to do this EVERY SINGLE TIME :) Is there a shortcut or setting to have this done automatically?
Consider using console.table().
To expand / collapse a node and all its children,
Ctrl + Alt + Click or Opt + Click on arrow icon
(note that although the dev tools doc lists Ctrl + Alt + Click, on Windows all that is needed is Alt + Click).
While the solution mentioning JSON.stringify is pretty great for most of the cases, it has a few limitations
It can not handle items with circular references where as console.log can take care of such objects elegantly.
Also, if you have a large tree, then ability to interactively fold away some nodes can make exploration easier.
Here is a solution that solves both of the above by creatively (ab)using console.group:
function expandedLog(item, maxDepth = 100, depth = 0){
if (depth > maxDepth ) {
console.log(item);
return;
}
if (typeof item === 'object' && item !== null) {
Object.entries(item).forEach(([key, value]) => {
console.group(key + ' : ' +(typeof value));
expandedLog(value, maxDepth, depth + 1);
console.groupEnd();
});
} else {
console.log(item);
}
}
Now running:
expandedLog({
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
})
Will give you something like:
The value of maxDepth can be adjusted to a desired level, and beyond that level of nesting - expanded log will fall back to usual console.log
Try running something like:
x = { a: 10, b: 20 }
x.x = x
expandedLog(x)
Also please note that console.group is non-standard.
Might not be the best answer, but I've been doing this somewhere in my code.
Update:
Use JSON.stringify to expand your object automatically:
> a = [{name: 'Joe', age: 5}, {name: 'John', age: 6}]
> JSON.stringify(a, true, 2)
"[
{
"name": "Joe",
"age": 5
},
{
"name": "John",
"age": 6
}
]"
You can always make a shortcut function if it hurts to type all that out:
j = function(d) {
return JSON.stringify(d, true, 2)
}
j(a)
Previous answer:
pretty = function(d)
{
var s = []
for (var k in d) {
s.push(k + ': ' + d[k])
}
console.log(s.join(', '))
}
then, instead of:
-> a = [{name: 'Joe', age: 5}, {name: 'John', age: 6}]
-> a
<- [Object, Object]
You do:
-> a.forEach(pretty)
<- name: Joe, age: 5
name: John, age: 6
Not the best solution, but works well for my usage. Deeper objects will not work so that's something that can be improved on.
option+Click on a Mac. Just discovered it now myself and have made my week! This has been as annoying as anything
By default the console on Chrome and Safari browsers will output objects which are collapsed, with sorted property keys, and include all inherited prototype chains.
I'm personally not a fan. Most developers need raw output of an object without the prototype chain, and anything else should be opt-in. Collapsed objects waste the developer's time, because they need to expand them, and if they wanted less output they could just log the property keys they need. Auto-sorting the property keys, leaves the developer without a way to check if their own sort works correctly, which could cause bugs. And lastly, the common Javascript developer does not spend much time working on the inherited prototype chain, so that adds noise to the logs.
How to expand objects in Console
Recommended
console.log(JSON.stringify({}, undefined, 2));
Could also use as a function:
console.json = object => console.log(JSON.stringify(object, undefined, 2));
console.json({});
"Option + Click" (Chrome on Mac) and "Alt + Click" (Chrome on Window)
However, it's not supported by all browsers (e.g. Safari), and Console still prints the prototype chains, auto-sorts property keys, etc.
Not Recommended
I would not recommend either of the top answers
console.table() - this is shallow expansion only, and does not expand nested objects
Write a custom underscore.js function - too much overhead for what should be a simple solution
Here is a modified version of lorefnon's answer which does not depend on underscorejs:
var expandedLog = (function(MAX_DEPTH){
return function(item, depth){
depth = depth || 0;
isString = typeof item === 'string';
isDeep = depth > MAX_DEPTH
if (isString || isDeep) {
console.log(item);
return;
}
for(var key in item){
console.group(key + ' : ' +(typeof item[key]));
expandedLog(item[key], depth + 1);
console.groupEnd();
}
}
})(100);
Here is my solution, a function that iterates an all the properties of the object, including arrays.
In this example I iterate over a simple multi-level object:
var point = {
x: 5,
y: 2,
innerobj : { innerVal : 1,innerVal2 : 2 },
$excludedInnerProperties : { test: 1},
includedInnerProperties : { test: 1}
};
You have also the possibility to exclude the iteration if the properties starts with a particular suffix (i.e. $ for angular objects)
discoverProperties = function (obj, level, excludePrefix) {
var indent = "----------------------------------------".substring(0, level * 2);
var str = indent + "level " + level + "\r\n";
if (typeof (obj) == "undefined")
return "";
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
var propVal;
try {
propVal = eval('obj.' + property);
str += indent + property + "(" + propVal.constructor.name + "):" + propVal + "\r\n";
if (typeof (propVal) == 'object' && level < 10 && propVal.constructor.name != "Date" && property.indexOf(excludePrefix) != 0) {
if (propVal.hasOwnProperty('length')) {
for (var i = 0; i < propVal.length; i++) {
if (typeof (propVal) == 'object' && level < 10) {
if (typeof (propVal[i]) != "undefined") {
str += indent + (propVal[i]).constructor.name + "[" + i + "]\r\n";
str += this.discoverProperties(propVal[i], level + 1, excludePrefix);
}
}
else
str += indent + propVal[i].constructor.name + "[" + i + "]:" + propVal[i] + "\r\n";
}
}
else
str += this.discoverProperties(propVal, level + 1, excludePrefix);
}
}
catch (e) {
}
}
}
return str;
};
var point = {
x: 5,
y: 2,
innerobj : { innerVal : 1,innerVal2 : 2 },
$excludedInnerProperties : { test: 1},
includedInnerProperties : { test: 1}
};
document.write("<pre>" + discoverProperties(point,0,'$')+ "</pre>");
Here is the output of the function:
level 0
x(Number):5
y(Number):2
innerobj(Object):[object Object]
--level 1
--innerVal(Number):1
--innerVal2(Number):2
$excludedInnerProperties(Object):[object Object]
includedInnerProperties(Object):[object Object]
--level 1
--test(Number):1
You can also inject this function in any web page and copy and analyze all the properties, try in on the google page using the chrome command:
discoverProperties(google,0,'$')
Also you can copy the output of the command using the chrome command:
copy(discoverProperties(myvariable,0,'$'))
if you have a big object, JSON.stringfy will give error Uncaught TypeError: Converting circular structure to JSON
, here is trick to use modified version of it
JSON.stringifyOnce = function(obj, replacer, indent){
var printedObjects = [];
var printedObjectKeys = [];
function printOnceReplacer(key, value){
if ( printedObjects.length > 2000){ // browsers will not print more than 20K, I don't see the point to allow 2K.. algorithm will not be fast anyway if we have too many objects
return 'object too long';
}
var printedObjIndex = false;
printedObjects.forEach(function(obj, index){
if(obj===value){
printedObjIndex = index;
}
});
if ( key == ''){ //root element
printedObjects.push(obj);
printedObjectKeys.push("root");
return value;
}
else if(printedObjIndex+"" != "false" && typeof(value)=="object"){
if ( printedObjectKeys[printedObjIndex] == "root"){
return "(pointer to root)";
}else{
return "(see " + ((!!value && !!value.constructor) ? value.constructor.name.toLowerCase() : typeof(value)) + " with key " + printedObjectKeys[printedObjIndex] + ")";
}
}else{
var qualifiedKey = key || "(empty key)";
printedObjects.push(value);
printedObjectKeys.push(qualifiedKey);
if(replacer){
return replacer(key, value);
}else{
return value;
}
}
}
return JSON.stringify(obj, printOnceReplacer, indent);
};
now you can use JSON.stringifyOnce(obj)
Its a work around, but it works for me.
I use in the case where a control/widget auto updates depending on user actions. For example, when using twitter's typeahead.js, once you focus out of the window, the dropdown disappears and the suggestions get removed from the DOM.
In dev tools right click on the node you want to expand enable break on... -> subtree modifications, this will then send you to the debugger. Keep hitting F10 or Shift+F11 untill you dom mutates. Once that mutates then you can inspect. Since the debugger is active the UI of Chrome is locked and doesn't close the dropdown and the suggestions are still in the DOM.
Very handy when troubleshooting layout of dynamically inserted nodes that are begin inserted and removed constantly.
Another easier way would be
Use JSON.stringify(jsonObject)
Copy and Paste the result to Visual Studio Code
Use Ctrl+K and Ctrl+F to format the result
You will see formatted expanded object
I have tried this for simple objects.
You can package JSON.stringify into a new function eg
jsonLog = function (msg, d) {
console.log(msg + '\n' + JSON.stringify(d, true, 2))
}
then
jsonLog('root=', root)
FWIW.
Murray
For lazy folks
/**
* _Universal extensive multilevel logger for lazy folks_
* #param {any} value **`Value` you want to log**
* #param {number} tab **Abount of `tab`**
*/
function log(value, tab = 4) {
console.log(JSON.stringify(value, undefined, tab));
}
Usage
log(anything) // [] {} 1 true null
Alt-click will expand all child nodes in the Chrome console.
You could view your element by accessing document.getElementsBy... and then right click and copy of the resulted object. For example:
document.getElementsByTagName('ion-app') gives back javascript object that can be copy pasted to text editor and it does it in full.
Better yet: right click on the resulted element - 'Edit as html' - 'Select all' - 'Copy' - 'Paste'