Dynamically adding the columns in group by clause of linq - linq

I am getting a datatable from service. I am using linq to calculate of sum new columns. I want all the coumns in datatable originally plus the new columns calculated in linq.
Problem is columns in datatable are not fixed. How would I dynamically add the columns in select clause of linq.
Below is code snippet:
DataTable dt = ds.Tables[0];
var orderCtr =
from o in dt.AsEnumerable()
where o.Field<string>(Constants.GENDER_NAME) != "Unknown"
group o by new
{
odr_id = o.Field<int>(Constants.ORDER_ID),
//NEED TO ADD COLUMNS DYNAMICALLY HERE. MEANS IF THEY ARE IN DATATABLE.
}
into g
select new
{
//NEED TO ADD COLUMNS DYNAMICALLY HERE. MEANS IF THEY ARE IN DATATABLE.
odr_id = g.Key.odr_id,
ac_gr_imp = g.Sum(r => r.Field<long>(Constants.GENDER_IMPRESSION)),
ac_gr_clk = g.Sum(r => r.Field<long>(Constants.GENDER_CLICK)),
Ctr = (double)g.Sum(r => r.Field<long>(Constants.GENDER_IMPRESSION)) / g.Sum(r => r.Field<long>(Constants.GENDER_CLICK)),
};

You might be interested in the Dynamic LINQ library. Dynamic LINQ allows you to specify queries or parts of queries by building strings.
Scott Guthrie described it back in 2008 (http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx) and there is also a NuGet package of it in case you use .NET 4 (http://www.nuget.org/packages/System.Linq.Dynamic).

Related

How to write SQL translateable linq code that groups by one property and returns distinct list

I want to change code below to be sql translateable because now i get exception.
Basicallly i want list of customers from certain localisation and there could be more than one customer with the same CustomerNumber so i want to take the one that was most recently added.
In other words - distinct list of customers from localisation where "distinct algorithm" works by taking the most recently added customer if there is conflict.
The code below works only if it is client side. I could move Group By and Select after ToListAsync but i want to avoid taking unnecessary data from database (there is include which includes list that is pretty big for every customer).
var someData = await DbContext.Set<Customer>()
.Where(o => o.Metadata.Localisation == localisation)
.Include(nameof(Customer.SomeLongList))
.GroupBy(x => x.CustomerNumber)
.Select(gr => gr.OrderByDescending(x => x.Metadata.DateAdded).FirstOrDefault())
.ToListAsync();
Short answer:
No way. GroupBy has limitation: after grouping only Key and Aggregation result can be selected. And you are trying to select SomeLongList and full entity Customer.
Best answer:
It can be done by the SQL and ROW_NUMBER Window function but without SomeLongList
Workaround:
It is because it is not effective
var groupingQuery =
from c in DbContext.Set<Customer>()
group c by new { c.CustomerNumber } into g
select new
{
g.Key.CustomerNumber,
DateAdded = g.Max(x => x.DateAdded)
};
var query =
from c in DbContext.Set<Customer>().Include(x => x.SomeLongList)
join g in groupingQuery on new { c.CustomerNumber, c.DateAdded } equals
new { g.CustomerNumber, g.DateAdded }
select c;
var result = await query.ToListAsync();

Entity Framework Linq Update Table

I am using Entity Framework 6 Code First, all of my navigation properties looks correct. What I want to do in linq is to update multiple values in the one (entity) table with calculated values from the other (entity) table. The required outcome is the sql below,
UPDATE SalesDealItemChange
SET Price = SD.Rate * #FactorRate
FROM SalesDealItemChange SC
INNER JOIN [SalesDealItems] SD
ON SC.SalesDealItemID = sd.ID
WHERE SD.SalesDealID = #SalesDeal
I have tried the following linq, but i am not sure how to isolate the update to the SalesDealItemChange
context.SalesDealItems
.Include(x => x.SalesDealItemChanges)
.Where(x => x.SalesDealID == #SalesDeal)
.ForEach(x =>
{
x.SalesDealItemChanges.Price = x.ListPrice * #FactorRate;
});
context.SaveChanges();
Regards,

Summing and grouping in datatable

1.Requirement:
the above is the result of my datatable value
1. Need to group the states by summing the premium value
2. need to mention the address, city for the states which is having highesht premium values
3. Linq or for loop anything is fine for me, please help me out
thanks,
Srikanth Anantharaman
You could use this LINQ query to fill a second table:
DataTable newTable = tbl.Clone(); // empty table, same schema
var groupedByState = tbl.AsEnumerable()
.GroupBy(r => r.Field<string>("State"));
foreach(var group in groupedByState)
{
DataRow maxPremRow = group.OrderByDescending(r => r.Field<int>("Premium")).First();
DataRow newRow = newTable.Rows.Add();
newRow.SetField("State", group.Key);
newRow.SetField("Address", maxPremRow.Field<string>("Address"));
newRow.SetField("City", maxPremRow.Field<string>("City"));
newRow.SetField("Premium", group.Sum(r => r.Field<int>("Premium")));
}

Can we filter Datatable with LINQ?

Suppose my datatable is filled with data.
After filling data can we again put some condition on datatable with linq to extract data.
Suppose my datatable has 10 employee record.
So can we extract only those employee whose salary is greater than 5000 with linq query.
I know that we can achieve it datatable.select(). How can you achieve this with linq?
You can get a filtered set of rows, yes:
var query = table.AsEnumerable()
.Where(row => row.Field<decimal>("salary") > 5000m);
This uses the AsEnumerable and Field extension methods in DataTableExtensions and DataRowExtensions respectively.
Try this:
var query = (from t0 in dtDataTable.AsEnumerable()
where t0.Field<string>("FieldName") == Filter
select new
{
FieldName = t0.Field<string>("FieldName"),
FieldName2 = t0.Field<string>("FieldName2"),
});

Is there a pattern using Linq to dynamically create a filter?

Is there a pattern using Linq to dynamically create a filter?
I have the need to create custom filtering on a list, in the past I would just dynamically create the SQL...it doesn't seem like this is possible with Linq.
Check out the Dynamic Linq Library from ScottGu's blog:
For example, below is a standard type-safe LINQ to SQL VB query that retrieves data from a Northwind database and displays it in a ASP.NET GridView control:
Dim Northwind As New NorthwindDataContext
Dim query = From q In Northwind.Products Where p.CategoryID = 2 And p.UnitPrice > 3 Order By p.SupplierID Select p
Gridview1.DataSource = query
GridView1.DataBind()
Using the LINQ DynamicQuery library I could re-write the above query expression instead like so
Dim Northwind As New NorthwindDataContext
Dim query = Northwind.Products .where("CategoryID=2 And UnitPrice>3") . OrderBy("SupplierId")
Gridview1.DataSource = query
GridView1.DataBind()
Notice how the conditional-where clause and sort-orderby clause now take string expressions instead of code expressions. Because they are late-bound strings I can dynamically construct them. For example: I could provide UI to an end-user business analyst using my application that enables them to construct queries on their own (including arbitrary conditional clauses).
Dynamic Linq is one way to go.
It may be overkill for your scenario. Consider:
IQueryable<Customer> query = db.Customers;
if (searchingByName)
{
query = query.Where(c => c.Name.StartsWith(someletters));
}
if (searchingById)
{
query = query.Where(c => c.Id == Id);
}
if (searchingByDonuts)
{
query = query.Where(c => c.Donuts.Any(d => !d.IsEaten));
}
query = query.OrderBy(c => c.Name);
List<Customer> = query.Take(10).ToList();
Dynamically Composing Expression Predicates
something like this?
var myList = new List<string> { "a","b","c" };
var items = from item in db.Items
where myList.Contains(item.Name)
select item;
that would create a sql statement like
SELECT * FROM Items [t0] where Name IN ('a','b','c')

Resources