Pass dynamic data type to function - c#

I have the following function:
private string ParseJson(dynamic q)
{
string returnJSON = "[{ \"type\" : \"pie\", \"name\" : \"Campaigns\", \"data\" : [ ";
foreach (var grp in q)
{
double currCount = grp.Count();
if (grp.Key != null)
returnJSON += "['" + grp.Key + "', " + currCount + "],";
else
returnJSON += "['none', " + currCount + "],";
}
returnJSON = returnJSON.Substring(0, returnJSON.Length - 1);
returnJSON += "]}]";
return returnJSON;
}
I call it from methods like this one:
public string GetCampaignData()
{
PaymentModelDataContext db = new PaymentModelDataContext();
var q = from Event in db.TrackingEvents
group Event by Event.campaignID;
return ParseJson(q);
}
I use q for several different queries, all grouping data.
The problem is that the runtime can't bind a type to q for some reason. Is this a proper use of dynamic? Is there a different way to do this?

The problem is Count() is an extension method off of IEnumerable<T>, as such it can't be called from dynamic (because it's not a true method of the class).
Your variable grp is also dynamic because it results from an expression on dynamic variable q:
foreach (var grp in q)
Since we can't call extension methods off of dynamic (again, they aren't true members of the class), we need to explicitly call the extension method instead off the Enumerable static class. So change your code to:
double currCount = Enumerable.Count(grp);
And you'll see it work properly for the Count(), if you want to really use dynamic.
That said, I do agree with #John's comment that you should consider changing this to a non-dynamic. Actually, what your method would accept would be an IEnumerable> like so:
private string ParseJson<TKey,TValue>(IEnumerable<IGrouping<TKey,TValue>> q)
{
string returnJSON = "[{ \"type\" : \"pie\", \"name\" : \"Campaigns\", \"data\" : [ ";
foreach (var grp in q)
{
double currCount = grp.Count();
if (grp.Key != null)
returnJSON += "['" + grp.Key + "', " + currCount + "],";
else
returnJSON += "['none', " + currCount + "],";
}
returnJSON = returnJSON.Substring(0, returnJSON.Length - 1);
returnJSON += "]}]";
return returnJSON;
}
You can also make the parameter type non-generic specific to your usage if you like. But this would work with all groupings...

Related

How to filter date in server side using dynamic linq?

I want to filter dates range. I'm using the dynamic LINQ library. I have to build my where string into a variable based on several factors and then pass the string variable to the where clause.
In my ASP.NET MVC project I wrote a helper.
private string GetFilterCondition(string filterCondition, string filterDataField, string filterValue)
{
switch (filterCondition)
{
case "CONTAINS":
return " " + filterDataField + ".Contains(\"" + filterValue + "\")";
case "GREATER_THAN_OR_EQUAL":
return " " + filterDataField + " >= " +"\"" + filterValue + "\"";
case "LESS_THAN_OR_EQUAL":
return " " + filterDataField + " <= " + "\"" + filterValue + "\"";
}
return "";
}
And I used parameter in query which I've passed from the ASP.NET MVC project;
public int GetFilteredCount(string searchValue)
{
var filteredRecords = 0;
try
{
var query = DB.Categories.AsQueryable();
var totalRecords = query.Count();
if (!string.IsNullOrEmpty(searchValue))
{
searchValue = searchValue.Trim();
query = query.Where(searchValue);
}
filteredRecords = query.Count();
}
catch (Exception e){}
finally
{
DestroyDbContext();
}
return result;
}
When filtering date range ("GREATER_THAN_OR_EQUAL", "LESS_THAN_OR_EQUAL"), I get an error:
Operator '>=' incompatible with operand types 'DateTime' and 'String'
Please note, that with 'contains' works.
I uploaded picture to see what looks like searchvalue parameter
I rewrote GetFilterCondition function like this:
case "GREATER_THAN_OR_EQUAL":
return string.Format(" {0} >= DateTime.Parse(\"{1}\")", filterDataField, filterValue);
case "LESS_THAN_OR_EQUAL":
return string.Format(" {0} <= DateTime.Parse(\"{1}\")", filterDataField, filterValue);
after executed filteredRecords = query.Count() throws this error:
LINQ to Entities does not recognize the method 'System.DateTime Parse(System.String)' method, and this method cannot be translated into a store expression

Pass parameter to a method and read the return value?

Having this code:
var code = "public class TestClass {" +
" public int HelloWorld(int num) {" +
" return 5 + num;" +
" }" +
"}";
var script = CSharpScript.Create(code);
var x = (await script.RunAsync()).ReturnValue;
How does one pass a value for the parameter, call the method and read the return value?
Continue with another code is the simplest.
var call = await script.ContinueWith<int>("new TestClass().HelloWorld(3)").RunAsync();
var x = call.ReturnValue;
By the way, CSharpScript is a scripting engine which does not require you having class and method like ordinary C# program. You can just use 5 + num as script content.
var code = "5 + num";
var numValue = 3;
var setParam = await CSharpScript.RunAsync("var num = " + numValue + ";");
var runCode = await setParam.ContinueWithAsync(code);
var x = runCode.ReturnValue;
For full example, take a look of RoslynScript/Script.cs

How to access subObject properties values in c#

I am trying to loop over an object properties and values and build a string with them.
The problem is i cant seem to access the values of the properties which are not string...
Here is what i have so far:
private string ObjectToStringArray(CustomType initParameters)
{
var stringArray = "";
foreach (var parameter in initParameters.GetType().GetProperties())
{
if (parameter.PropertyType.Name == "String")
stringArray += "\"" + parameter.Name + "\" => \"" + parameter.GetValue(initParameters) + "\",\r\n";
else
{
stringArray += "array(\r\n";
foreach (var subParameter in parameter.PropertyType.GetProperties())
{
stringArray += "\"" + subParameter.Name + "\" => \"" + subParameter.GetValue(parameter) + "\",\r\n";
}
stringArray += "),";
}
}
return stringArray;
}
i can get to the values of all the string properties but one level down i just cant extract the property object itself.
My exception is: System.Reflection.TargetException: Object does not match target type.
When calling subParameter.GetValue(parameter), you are passing a PropertyInfo, whereas you seemingly want to pass the value of that property for initParameters instead.
You should thus pass parameter.GetValue(initParameters) to subParameter.GetValue() instead.

C#: SQL Query Builder Class

Where can I find a good SQL Query builder class. I just need a simple class to build a SQL string and that is it. I will need it for C# and MySql. I really don't need anything like Linq or NHibernate. Thanks
Since Google leads me to this page,
I would suggest SqlKata, a simple but powerful SqlQuery Builder, that supports nested where conditions, subqueries and joins.
Currently it supports SqlServer, MySql and PostgreSql
var query = new Query("Users")
.LeftJoin("Countries", "Users.CountryId", "Countries.Id")
.Where("Status", "blocked")
.OrWhereIn("Id", new [] {10, 11, 12})
.OrWhere("LastLogin", ">", DateTime.UtcNow.AddMonths(-5));
Note: I am the owner of it
Difference between different compilers output
MySql: https://sqlkata.com/playground/mysql?code=var%20query%20=%20new%20Query(%22Posts%22).Limit(10).Offset(20)%3B
SqlServer: https://sqlkata.com/playground/sqlserver?code=var%20query%20=%20new%20Query(%22Posts%22).Limit(10).Offset(20)%3B
Oracle: https://sqlkata.com/playground/oracle?code=var%20query%20=%20new%20Query(%22Posts%22).Limit(10).Offset(20)%3B
I use this code..It Escapes the strings too i hope it Helps:
class Mysql
{
public static string INSERT(string INTO, NameValueCollection VALUES)
{
string queryString = "INSERT INTO " + INTO + " (";
for (int i = 0; i < VALUES.Count; i++)
{
queryString += VALUES.Keys[i] + (i + 1 == VALUES.Count ? "" : ",");
}
queryString += ") VALUES (";
for (int i = 0; i < VALUES.Count; i++)
{
queryString += Escape(VALUES[VALUES.Keys[i]]) + (i + 1 == VALUES.Count ? ("") : (","));
}
queryString += ");";
return queryString;
}
public static string DELETE(string FROM, NameValueCollection WHERE)
{
string queryString = "DELETE FROM " + FROM + " WHERE";
for (int i = 0; i < WHERE.Count; i++)
{
queryString += " " + WHERE.Keys[i] + "=" + Escape(WHERE[WHERE.Keys[i]]);
}
queryString += ";";
return queryString;
}
public static string UPDATE(string UPDATE, NameValueCollection SET, NameValueCollection WHERE)
{
string queryString = "UPDATE " + UPDATE + " SET";
for (int i = 0; i < SET.Count; i++)
{
queryString += " " + SET.Keys[i] + "=" + data.Escape(SET[SET.Keys[i]]) + (i + 1 == SET.Count ? ("") : (","));
}
queryString += " WHERE";
for (int i = 0; i < WHERE.Count; i++)
{
queryString += " " + WHERE.Keys[i] + "=" + data.Escape(WHERE[WHERE.Keys[i]]);
}
queryString += ";";
return queryString;
}
public static string SELECT(string[] SELECT, string FROM, NameValueCollection WHERE)
{
string queryString = "SELECT ";
for (int i = 0; i < SELECT.Length; i++)
{
queryString += SELECT[i] + (i + 1 == SELECT.Length ? ("") : (","));
}
queryString += " FROM " + FROM + " WHERE ";
for (int i = 0; i < WHERE.Count; i++)
{
queryString += " " + WHERE.Keys[i] + "=" + Escape(WHERE[WHERE.Keys[i]]);
}
queryString += ";";
return queryString;
}
public static string Escape(string input)
{
using (var writer = new StringWriter())
{
using (var provider = CodeDomProvider.CreateProvider("CSharp"))
{
provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, null);
return writer.ToString();
}
}
}
}
You use it like this:
NameValueCollection nvc_for_SET_and_VALUES=new NameValueCollection();
NameValueCollection nvc_for_WHERE= new NameValueCollection();
nvc_for_WHERE.Add("arg1","value1");
nvc_for_WHERE.Add("AND arg2","value2");
nvc_for_WHERE.Add("OR arg2","value3");
nvc_for_SET_and_VALUES.Add("arg", "value");
nvc_for_SET_and_VALUES.Add("arg2", "value2");
string[] fieldsToSelect= { "arg1", "arg2" };
Mysql.DELETE("mytable", nvc_for_WHERE);
Mysql.INSERT("mytable", nvc_for_SET_and_VALUES);
Mysql.SELECT(fieldsToSelect, "mytable", nvc_for_WHERE);
Mysql.UPDATE("mytable", nvc_for_SET_and_VALUES, nvc_for_WHERE);
You could probably use the framework class CommandBuilder. Check out:
http://msdn.microsoft.com/en-us/library/tf579hcz.aspx
If you are using .NET 4 and don't mind using dynamics you can use Massive, created by Rob Conery, this single file Database requires no dlls, just drop the Massive.cs file and you ready to go.
You can use the Massive to build queries like this.
//grab all the products
var products = table.All();
//Or
var productsFour = table.All(columns: "ProductName as Name", where: "WHERE categoryID=#0",args: 4);
You can also run ad-hoc queries as needed:
var result = tbl.Query("SELECT * FROM Categories");
Mohammed Hadi, with DbExtensions your sample can be like this:
public static string InsertQuery(string into, NameValueCollection values)
{
var query = SQL
.INSERT_INTO(into + " (" +
String.Join(" ,", values.Keys.Cast<String>().ToArray()) +
")")
.VALUES(values.Keys.Cast<String>().Select(key => values[key]));
return query.ToString();
}

error: The query results cannot be enumerated more than once

Edit:
DataClassesDataContext dc = new DataClassesDataContext();
string _idCompany = Request["idCompany"];
var newes = dc.GetNewsCompany(Int64.Parse(_idCompany));
string date = "";
string newsHtml = "<center>";
if(newes.GetEnumerator().MoveNext()){
foreach (var item in newes)//say Error .......................
{
// date = calendar.GetDayOfMonth(item.DateSend) + "/" + calendar.GetMonth(item.DateSend) + "/" + calendar.GetYear(item.DateSend).ToString();
// newsHtml += "<li class='news-item'><a style='text-decoration:none' class=\"link\" onclick=\"$(\'#BodyNews\').text(\'" + HttpUtility.HtmlEncode(item.Body).Trim() + "\');$(\'#BodyNews\').dialog({resizable:false});\" href=\"#\" > " + item.Title.ToString() + "</a> " + date + " </li>";
}
newsHtml += "</center>";
}
else
{
// var propertyCompany = dc.GetPropertyCompanyById(Int64.Parse(_idCompany));
// newsHtml += "<li class='news-item'><a style='text-decoration:none' class=\"link\" );$(\'#BodyNews\').dialog({resizable:false});\" href=\"#\" > " + "!به صفحه شخصی شرکت " + propertyCompany.FirstOrDefault().NameCompany + " خوش آمدید " + "</a> " + date + " </li>";
}
return newsHtml;
say error:The query results cannot be enumerated more than once
how check var is empty or null with out enumerated;
Why bother with the if at all?
var newes = dc.GetNewsCompany(Int64.Parse(_idCompany));
//if (newes.GetEnumerator().MoveNext())//check is null or empty
var newesList = newes.ToList();
if (neweList.Count > 0)
{
...
}
You can always check the newesList.Count property afterward.
Not sure what's available as a member in newes, but if it's an object and depending on what dc.GetNewsCompany returns you could check for null
if (news == null) return;
or if it returns an empty collection/array, just check the count/length:
if (news.Count == 0) return;
if (news.Length == 0) return;
the error comes, because you are using .GetEnumerator() on newes and then using the newes again in a foreach Loop .. this causes the "double enumeration".
Generally avoid walking "such var"'s with a foreach, since the DataReader is locked the whole loop !. Means that you cannot use the same entitie in this loop.
Better .ToList() , you can the list.AsQuearable agian if you want to Linq on it
f.e. something like
var newes = dc.CompanyTable.Where(ln => ln.id.Equals(_idCompany));;
List<CompanyTable> newesList = newes.ToList();

Categories