Linq to dataset on dynamic columns and dynamic group by fields - linq

I have four parameters to my function a dataset, array consisting of expressions (aggregate functions), array consisting of column names on which to apply expressions and an array consisting of columns on which I have to group by.
My problem is how can I handle dynamic columns or fields for expression and group by as it can vary in numbers (depends on array values).
I have written code for static query, but need a generic way...
This is my code:
public void ExpressionManipulation(DataSet dsExprEvaluate, string[] strExpressions, string[] colName, string[] groupbyFields)
{
int groupByLength = groupbyFields.Length;
var groupByQueryEvaluate = from table in dsExprEvaluate.AsEnumerable()
group table by new { column1 = table["DataSourceType"], column2 = table["Polarity"] }
into groupedTable
select new
{
x = groupedTable.Key, // Each Key contains column1 and column2
y = groupedTable.Count(),
//z = groupedTable.Max(column1),
z = groupedTable.Sum(table => Convert.ToInt32(table["Polarity"]))
};
}
Like in above I can have n number of fields in group by like for now I have taken only two (DataSourceType and Polarity) and similar I can have n number of fields for expressions, for sum, count etc which will be as an array as parameter.
Please help me through this, it is driving me crazy.
Thanks in advance.

I figured it out myself and the solution i ended up is with:
var objGroupSumCountkey = dt.AsEnumerable()
.AsQueryable()
.GroupBy("new ( it[\"DataSourceType\"] as GroupByColumnName1,it[\"Polarity\"] as GroupByColumnName2)", "it")
.Select("new ( Sum(Convert.ToDouble(it[\"Polarity\"].ToString())) as SumValue,Count() as TotalCount,it.key)");
in the above query all the parameters will be supplied as string, in Group By and select

Related

Access field value in a function in Power Query M

I want to create a function that gets the first value of a table field if two other field values match the two given function parameters.
I thought this would be easy. But I found nothing in the internet or M documentation that could solve this.
I don't know if I have to loop through a record or if there is a top level function.
= (val1 as text, val2 as text) as text =>
let
result = if [Field1] = val1 and [Field2] = val2 then [Field3] else ""
in
result
As far as I understand your wish, table and column names are hard coded (i.e. you intend to apply the function only for specific table). Then you may use following approach:
// table
let
t1 = #table({"Field1"}, List.Zip({{"a".."e"}})),
t2 = #table({"Field2"}, List.Zip({{"α".."ε"}})),
join = Table.Join(t1&t1,{}, t2&t2,{}),
add = Table.AddIndexColumn(join, "Field3", 0, 1)
in
add
// func
(val1 as text, val2 as text) => Table.SelectRows(table, each [Field1] = val1 and [Field2] = val2)[Field3]{0}
// result
func("d","β") //31

Group lines with Numeric and AlphaNumeric (LINQ)

I have a dataset with a column having Numeric and AlphaNumeric Order Nos. Data is being grouped up with different columns which result in merging rows together. Now I want to group lines based on Numeric and AlphaNumeric Order Nos as well, for that purpose I have to evaluate string (data) whether it is Numeric or AlphaNumeric. Following is the statement which groups up data together.
var groupLinesETAFile = (from g in strLinesETAFile
group g by new
{
g.PONo,
g.POLineNo,
g.POSubLineNo,
g.AllocatedPartNo
} into grouped
select new
{
PONo = grouped.Key.PONo,
POLineNo = grouped.Key.POLineNo,
POSubLineNo = grouped.Key.POSubLineNo,
AllocatedPartNo = grouped.Key.AllocatedPartNo,
ETAQty = grouped.Sum(x => decimal.Parse(x.ETAQty))
}).ToList();
Now I want to add a new column in statement "SupplierOrderNo" which has Numeric and AlphaNumeric Values and want to group on Numeric and AlphaNumeric values as well. How can I achieve this with LINQ?

How to query and calculate dates in the where clause of a LINQ statement?

I am having trouble with the following piece of code. Before I paste it, Let me give a bit of history on what should happen.
I have a model containing 2 fields of interest at the moment, which is the name of the order the customer placed, and the date at which he/she placed it. A pre-calculated date will be used to query the dateplaced field (and should only query the dates , and not the time). The query counts the amount of duplicates that occur in the MondayOrder field, and groups them together. Now , when I exclude the where clause which should query the dates, the query runs great. However, The goal of this query is to count the amount of orders for the following week based on the date the order has been placed.
List<string> returnlist = new List<string>();
DateTime dt = getNextWeekMondaysDate().Date;
switch (day)
{
case DayOfWeek.Monday:
{
var CountOrders =
from x in Data.EntityDB.Orders
group x by x.MondayOrder into m
let count = m.Count()
select new
{
MondayOrderItem = m.Key, Amount = count
};
foreach (var item in CountOrders)
{
returnlist.Add(item.MondayOrderItem + " : " +
item.Amount);
}
}
break;
The getNextWeekMondaysDate() method has an overload which I can use, where if I supply it a date, it will get the following Monday's date from the parameter given. The problem is though, LINQ does not accept queries such as the following:
var CountOrders =
from x in Data.EntityDB.Orders
where getNextWeekMondaysDate(x.DatePlaced.Value).Date == dt
group x by x.MondayOrder into m
let count = m.Count()
select new { MondayOrderItem = m.Key, Amount = count };
This is exactly what I must achieve. Is there any workaround for this situation?
UPDATE
Here is the exception I get when I try the 2nd query.
LINQ to Entities does not recognize the method 'System.DateTime getNextWeekMondaysDate(System.DateTime)' method, and this method cannot be translated into a store expression.
You cannot do this directly, as user-defined method calls cannot be translated to SQL by the EF query provider. The provider recognizes a limited set of .NET methods that can be translated to SQL and also a number of canonical functions as well. Anything that cannot be expressed using these methods only is off-limits unless you write your own query provider (which is only theoretically an option).
As a practical workaround, you can calculate an appropriate range for x.DatePlaced.Value in code before the query and then use specific DateTime values on the where clause.
As an intellectual exercise, note that this method is recognized by the query provider and can be used as part of the expression. So this abomination should work too:
var CountOrders =
from x in Data.EntityDB.Orders
where EntityFunctions.AddDays(
x.DatePlaced.Date.Value,
(9 - DateAndTime.DatePart(DateInterval.WeekDay, x.DatePlaced.Value)) % 7)
.Date == dt
group x by x.MondayOrder into m
let count = m.Count()
select new { MondayOrderItem = m.Key, Amount = count };
Linq to Entities doesn't know how to convert arbitrary C# methods into SQL - it's not possible in general.
So, you have to work with the methods it does understand.
In this case, you could do something like this:
DateTime weekBegin = CalculateWeekBegin( dt );
DateTime weekEnd = CalculateWeekEnd( dt );
var CountOrders =
from x in Data.EntityDB.Orders
where x.DatePlaced.Value >= weekBegin && x.DatePlaced.Value < weekEnd
group x by x.MondayOrder into m
let count = m.Count()
select new { MondayOrderItem = m.Key, Amount = count });

LINQ : How to check CONTAINS with multiple dynamic input values

I am facing a problem regarding a LINQ query.
I have multiple input values which is stored in List< string > variable.
I have to form a LINQ query which would have a where clause which check for the respective column with CONTAINS keyword. The issue I am facing is that List< string > can contain any number of values in it.
So i want to know how can i form a query which can read input values from collection object. and display the result.
Any suggestion would be appreciated.
Thanks in advance.
Linq extension method:
public static bool ContainsAny<T>(this IEnumerable<T> Collection, IEnumerable<T> Values)
{
return Collection.Any(x=> Values.Contains(x));
}
Then you can use like:
List<string> List1 = getStringList1();
List<string> List2 = getStringList2();
bool List2ItemsInList1 = List1.ContainsAny(List2);
Your question is not clear. Suppose you have three values X, Y and Z. If you want to fetch the results where a Column is either X, Y or Z, then habib-osu's answer will do this.
If you are looking for all records where a particular column contains X, Y and Z then the following should work
List<string> options = new List<string>();
options.Add("X");
options.Add("Y");
options.Add("Z");
var query = (from r in dc.Table select r);
foreach(var option in options)
query = (from r in query where r.Column.Contains(option) select r);
var list = query.ToList();
This will produce one sql query similar to the following
select * from Table where Column like '%X%' and column like '%Y%' and column like '%Z%'

LINQ Distinct set by column value

Is there a simple LINQ query to get distinct records by a specific column value (not the whole record)?
Anyone know how i can filter a list with only distinct values?
You could use libraries like morelinq to do this. You'd be interested in the DistinctBy() method.
var query = records.DistinctBy(record => record.Column);
Otherwise, you could do this by hand.
var query =
from record in records
group record by record.Column into g
select g.First();
Select a single value first and then run the Distinct.
(from item in table
select item.TheSingleValue).Distinct();
If you want the entire record you need to use group x by into y. You then need to find a suitable aggregate function like First, Max, Average or similar to select one of the other values in the group.
from item in table
group item by item.TheSingleValue into g
select new { TheSingleValue = g.Key, OtherValue1 = g.First().OtherValue1, OtherValue2 = g.First().OtherValue2 };
You could make an implementation of the IEqualityComparer interface:
public class MyObjectComparer : IEqualityComparer<MyObject>
{
public bool Equals(MyObject x, MyObject y)
{
return x.ColumnNameProperty == y.ColumnNameProperty;
}
public int GetHashCode(MyObject obj)
{
return obj.ColumnNameProperty.GetHashCode();
}
}
And pass an instance into the Distinct method:
var distinctSource = source.Distinct(new MyObjectComparer());

Resources