Using dynamic type in LINQ queries - c#

I'm using LINQ for querying the database. I'm using dynamic keyword in queries. I don't know this dynamic mechanism in depth, so I don't understand what's going on.
The situation follows. The following section of code:
var qGroup = qLocalOrd.GroupBy("new(...)", "it");
var qGroupCast = (qGroup as IQueryable<IGrouping<dynamic,dynamic>>).AsEnumerable();
var qAgg = from ordg in qGroupCast
select new {
ordg.Key,
Agg = (ordg.Key.OsID + " " + ordg.Key.NameOs + "\n" +
(ordg as IEnumerable<dynamic>).Aggregate("Составные части:\n", ...).Trim('\n') + ...)
};
Works just fine. But when I'm adding this to the end:
var qPlain = qAgg.Cast<dynamic>().AsQueryable().Select("new(Key.SubSchet, Key.NameSubSchet, ...)");
qPlain.Dump();
I'm receiving an error like "No field "Key" exists in type "Object"". It's the same if I use
(qAgg as IEnumerable<dynamic>)
So at this point dynamic treatment of qAgg elements is broken somewhy.
Why does this happen and how to make this thing work?

Related

Put single quote in each values inside a string in C#

I am trying to put a single quote in each values in a string that is separated by comma to include it in an SQL query (ex. "AND STAT IN ('11', '12'). Please help me if you have any ideas.
Sample data: string sStatus = "10,20,30,40";
I have already tried splitting each of the values.
if (!String.IsNullOrEmpty(sStatus))
{
string[] sStatList = sStatus.Split(',');
foreach (string p in sStatList)
{
}
sFilter = String.Format(" AND STAT IN ({0})", sStatList);
}
You can use Select().
string[] sStatList = sStatus.Split(',');
var res = string.Join(",", sStatList.Select(s => $"'{s}'"));
This requires using System.Linq;.
try this:
string[] sStatList = sStatus.Split(',');
string sFilter= "";
foreach (string p in sStatList)
{
sFilter = sFilter+ ("'" + p + "',");
}
if(sFilter.EndsWith(","))
{
sFilter = sFilter.Substring(0,sFilter.Length-1);
}
sFilter = " AND STAT IN (" + sFilter + ")";
#oika's answer is on the right track but it's not quite right for what you're trying to do. However Select is the answer here... like this though:
You'll need to add a reference to Linq:
using System.Linq;
Then
var sStatuses = sStatus.Split(',');
var parsedsStatuses = string.Join(",", sStatuses.Select(x => $"'{x}'"));
var sql = $"AND STAT IN ({ parsedsStatuses })";
Of course you do want to be careful doing this, as it opens up a vulnerability for SQL Injection.
You can either use the string.Join like this:
var status = "10,20,30,40";
if (!string.IsNullOrEmpty(status))
{
var sStatList = status.Split(',');
filter = $"'{string.Join("','", sStatList)}'";
}
Another option you have, would be to use the string.Replace:
var status = "10,20,30,40";
filter = $"'{status.Replace(",","','")}'";
Either way, you need to validate the input to avoid SQL Injection. Consider following:
status = "10,20,30');/*,*/ DROP TABLE Users;//";
Dapper for example supports this directly:}
var sql = "SELECT * FROM table WHERE Id IN #ids"
var results = connection.Query(sql, status.Split(','));
and there are alternative orms that will handle parameterisation.
As a side note: avoid using the Hungarian notation in C# as microsoft also recommends. The Hungarian notation where you specify the variable type using a prefix is useless information and adds noise, especially VS and VS Code will tell you the type anyway.

How to fix 'No property or field exists in type' error?

I got this error when trying to sort any columns that are not in the Order table, if I use OrderBy("Customer.CompanyName" + " " + sortDir) the error will gone but all the columns will become unable to sort. The OrderBy method used below come from here.
What is the cause of the problem ?
public ActionResult WebGrid(int page = 1, int rowsPerPage = 10, string sortCol = "OrderID", string sortDir = "ASC")
{
List<Order> res;
using (var nwd = new NorthwindEntities())
{
var _res = nwd.Orders
.OrderBy(sortCol + " " + sortDir)
.Select(o => new Order
{
OrderID = o.OrderID,
OrderDate = o.OrderDate,
CompanyName = o.Customer.CompanyName,
FirstName = o.Employee.FirstName,
//......
//......
//......
});
The class you provided the link to is marked as internal and it can't be used outside the assembly it was defined in, so you can't use it in your code.
This API supports the product infrastructure and is not intended to be
used directly from your code. Provides functionality to create new
classes from values in a LinqDataSource control.
So What you're actually trying to use is OrderBy inside Queryable class which is part of System.Linq which can be used as following:
.OrderBy(x=> x.sortCol + " " + x.sortDir)
If you're trying to order by two columns, then you can use:
.OrderBy(x=> x.sortCol).ThenBy(x=> x.sortDir)
If you want to dynamically specify the OrderBy expression, you can either do a switch statement for each possible parameter, or follow this SO Answer to build a dynamic Expression Tree.

Procedurally create a dynamic object for Dapper

I've seen many posts about creating ExpandoObject objects and such, but it does not work in my case. I need to create an object like
var someObj = new {
term1 = "someValue",
term2 = "other",
...
};
Basically, we are using Dapper and we need to create a query dynamically, where the WHERE clause is fabricated from a given array of arguments. We are not generalizing queries! It's a single method receiving a variable number of arguments and we need to check OR each value on a single column.
Right now, the only viable solution is to revert and directly use System.Data.SqlClient.SqlConnection, or is there any way to make this work?
Update:
This is what most likely should work, but doesn't :
string inWhere = null;
dynamic inTerms = new ExpandoObject();
IDictionary<string, object> inTermsDict = inTerms;
if (!(string.IsNullOrEmpty(filter.Term) || string.IsNullOrWhiteSpace(filter.Term))) {
inWhere = "(" + string.Join(" OR ", filter.Terms.Select((t, i) => "{0} LIKE #p" + i)) + ")";
int termIndex = 0;
foreach (string term in filter.Terms) {
inTermsDict.Add("p" + (termIndex++), term);
}
}
// ...
var rows = db.Query("SELECT * FROM {table} WHERE {baseCondition}" +
(string.IsNullOrEmpty(inWhere) ? "" : string.Format(" AND " + inWhere, "columnName")),
inTerms as object);
Just to answer my own question, as we found the proper solution earlier today.
Simply put, we found the IDynamicParameters And this class simply solves everything, acting as a Dictionary.
var inTerms = new Dapper.DynamicParameters();
inTerms.Add("#p" + (termIndex++), somveValue);
Everyone's happy!

sort two columns by value edited

form.myDataTable.Rows[i][2 * cs] = corr;
form.myDataTable.Rows[i][2 * cs + 1] = "p" + Convert.ToString(col1)
+ " p" + Convert.ToString(col2);
I need to sort 2*cs column by values and also corresponding names in column 2*cs+1.
I am trying like this:
var corrvalues = new Dictionary();
correlationvalues["p" + Convert.ToString(col1)
+ " p" + Convert.ToString(col2)] = corr;
sortedvalues = correlationvalues.Values.OrderByDescending;
I am not clear how to use orderbydescending, i am new to c#. Thanks for help.
OrderByDescending is a function, not a property. It has one required parameter, which is a function that takes a value in the collection (in your case, correctionvalues.Values) and returns a "key" to use for comparison purposes. If you just want to compare directly on the values themselves, you can pass in an identity lambda function (e.g. x => x).
var corrvalues = new Dictionary();
correlationvalues["p" + Convert.ToString(col1)
+ " p" + Convert.ToString(col2)] = corr;
sortedvalues = correlationvalues.Values.OrderByDescending(val => val);
If your values are more complex types (such as a Person class) and you want to sort on a particular field (such as Name), then you could pass in something like this:
sorted = personDict.Values.OrderByDescending(person => person.Name);
See http://msdn.microsoft.com/en-us/library/system.linq.enumerable.orderbydescending.aspx for more detail on OrderByDescending.
You can also learn more about lambda expressions (which is useful if you're new to C#) here: http://msdn.microsoft.com/en-us/library/bb397687.aspx

Sharepoint list Dynamic Linq query

I need to query a list in SharePoint where the columns may be added in the future.
For instance at the moment I have the following columns
Name, Job, interests, address
I want to be able to query this string dynamically using a parameter from the browser so if columns are added in the future I don’t have to change the code but just the parameter.
The address may look like this www.contoso.com/sites/mypage.aspx?property=Interests
And the code something on the line of this:
var SiteParameter = Request.QueryString["property"];
var ItemsFromList = from item in ListItems where item[try to put the parameter in here] select item;
I use SPmetal to get the list details, so if I press item. Visual Studio2010 will return the columns within the list.
This may be easier without SPMetal.
var qy = new SPQuery();
qy.Query =
"<Where><Eq>" +
"<FieldRef Name=`" + siteParameter + "'/>" +
// You may have to worry about the type of the field here, too.
"<Value Type='Text'>" + desiredValue + "</Value>" +
"</Eq></Where>";
var itemCollection = myList.GetItems(qy);

Categories

Resources