Not able to retrieve sum of varchar column using LINQ in c# - c#

var a = 123;
var query = (from p in a where p.ID == a) //gives 10 records.
.Sum(Convert.Int32.Parse(x => x.balance); // this line gives the following message.
Error Message.
LINQ to Entities does not recognize the method 'Int32 ToInt32 (System.String)',
Database design for the varchar column can't change to int or double.

var a = 123;
var sum = (from p in a where p.ID == a) //gives 10 records.
.Sum(x => int.Parse(x.balance));
var sum = (from p in db.table where p.ID == a)
.AsEnumerable() // #juharr's suggestion
.Sum(x => Convert.ToInt32(x.balance));
You want to convert the string in each iteration.. not the loop itself
This assumes the balance is a string and not an int already

If Entity Framework (or Linq-to-SQL, not sure what ORM are you using) can't translate something to SQL syntax, you can always try to resolve the query "C#-side" or client-side.
If you add .ToList() before the .Sum(), that should force the query to resolve on the database, and then the .Sum(...) and the .ToInt32() will be executed in memory.
var sum = (from p in db.table where p.ID == a)
.ToList()
.Sum(x => Convert.ToInt32(x.balance));

Related

How to write linq query for this sql statement

How would you write a linq query with the following SQL statement. I've tried several methods referenced on stackoverflow but they either don't work with the EF version I'm using (EF core 3.5.1) or the DBMS (SQL Server).
select a.ProductID, a.DateTimeStamp, a.LastPrice
from Products a
where a.DateTimeStamp = (select max(DateTimeStamp) from Products where a.ProductID = ProductID)
For reference, a couple that I've tried (both get run-time errors).
var results = _context.Products
.GroupBy(s => s.ProductID)
.Select(s => s.OrderByDescending(x => x.DateTimeStamp).FirstOrDefault());
var results = _context.Products
.GroupBy(x => new { x.ProductID, x.DateTimeStamp })
.SelectMany(y => y.OrderByDescending(z => z.DateTimeStamp).Take(1))
Thanks!
I understand you would like to have a list of the latest prices of each products?
First of all I prefer to use group by option even over 1st query
select a.ProductID, a.DateTimeStamp, a.LastPrice
from Products a
where a.DateTimeStamp IN (select max(DateTimeStamp) from Products group by ProductID)
Later Linq:
var maxDateTimeStamps = _context.Products
.GroupBy(s => s.ProductID)
.Select(s => s.Max(x => x.DateTimeStamp)).ToArray();
var results = _context.Products.Where(s=>maxDateTimeStamps.Contains(s.DateTimeStamp));
-- all assuming that max datetime stamps are unique
I've managed to do it with the following which replicates the correlated sub query in the original post (other than using TOP and order by instead of the Max aggregate), though I feel like there must be a more elegant way to do this.
var results = from x
in _context.Products
where x.DateTimeStamp == (from y
in _context.Products
where y.ProductID == x.ProductID
orderby y.DateTimeStamp descending
select y.DateTimeStamp
).FirstOrDefault()
select x;
I prefer to break up these queries into IQueryable parts, do you can debug each "step".
Something like this:
IQueryable<ProductOrmEntity> pocoPerParentMaxUpdateDates =
entityDbContext.Products
//.Where(itm => itm.x == 1)/*if you need where */
.GroupBy(i => i.ProductID)
.Select(g => new ProductOrmEntity
{
ProductID = g.Key,
DateTimeStamp = g.Max(row => row.DateTimeStamp)
});
//// next line for debugging..do not leave in for production code
var temppocoPerParentMaxUpdateDates = pocoPerParentMaxUpdateDates.ToListAsync(CancellationToken.None);
IQueryable<ProductOrmEntity> filteredChildren =
from itm
in entityDbContext.Products
join pocoMaxUpdateDatePerParent in pocoPerParentMaxUpdateDates
on new { a = itm.DateTimeStamp, b = itm.ProductID }
equals
new { a = pocoMaxUpdateDatePerParent.DateTimeStamp, b = pocoMaxUpdateDatePerParent.ProductID }
// where
;
IEnumerable<ProductOrmEntity> hereIsWhatIWantItems = filteredChildren.ToListAsync(CancellationToken.None);
That last step, I am putting in an anonymous object. You can put the data in a "new ProductOrmEntity() { ProductID = pocoMaxUpdateDatePerParent.ProductID }...or you can get the FULL ProductOrmEntity object. Your original code, I don't know if getting all columns of the Product object is what you want, or only some of the columns of the object.

Get last 2 rows from group on database side

I'm trying to improve performance of linq query for PostgreSQL. There are two tables (Parcles, ParcelStates) with relation 1:n. I need to get last 2 ParcelStates for each Parcel. Looks simple, I have following code:
IQueryable<Parcel> parcels = _dbContext.Parcels
.OrderByDescending(x => x.Id)
.Take(100);
Then getting states:
var states = await parcels
.GroupJoin(_dbContext.ParcelStates, ps => ps.Id, p => p.ParcelId, (ps, p) => new { ps, p })
.SelectMany(x => x.p.DefaultIfEmpty().OrderByDescending(y => y.Id).Take(2), (x,c) => c)
.ToListAsync();
It returns me 180 states, and it is ok. But there is performance issue, because it generates not perform SQL query:
SELECT *
FROM (
SELECT *
FROM parcels AS x
WHERE x.isdeleted = FALSE
ORDER BY c DESC, c0 DESC
LIMIT #__p_1 OFFSET #__p_0
) AS t
LEFT JOIN parcelstates AS p ON t.id = p.parcelid
ORDER BY t.c DESC, t.c0 DESC, t.id
It takes all states from database, when I need only 2.
How to change LINQ to filter result on database side?
In logs I found:
The LINQ expression 'Take(2)' could not be translated and will be evaluated
If you insert the SelectMany expression into the GroupJoin, will it convert to SQL?
var states = await parcels
.GroupJoin(_dbContext.ParcelStates, ps => ps.Id, p => p.ParcelId,
(ps, p) => p.DefaultIfEmpty().OrderByDescending(y => y.Id).Take(2))
.ToListAsync();
We can use a foreach loop which will translate to several very fast SQL lookups (should execute in < 1 second). Not ideal but I would still recommend writing a stored procedure to get this data, instead of relying on LINQ to SQL which doesn't always generate the most optimum query:
// Store a list of parcel states
var parcelStates = new List<ParcelState>();
// Read top 100 parcels from the database
var parcels = dbContext.Parcels
.OrderBy(p => p.Id)
.Take(100);
// For each parcel, use SQL to lookup the 2 most recent parcel states
foreach (var p in parcels)
{
var ps = dbContext.ParcelStates
.Where(ps => ps.ParcelId == p.Id)
.OrderByDescending(ps => ps.Id)
.Take(2);
parcelStates.AddRange(ps);
}
// Now we have all parcel states for those parcels
Console.WriteLine($"Found {parcelStates.Count} parcel states for {parcels.Count} parcels");

how to use linq to return a value from 4 tables

I am reasonably new to Linq and it seems quite easy to iuse but I am having an issue when trying to extract a value from a table that is linked/constrained by 3 other tables.
I have this in my SQL DB:
I am using Asp.Net 4 and Entity Framework 6.
I have as a parameter the 'DatabaseName'.
I ultimately want to get the SubscriptionRef that is assigned to this name.
I could do this step-by-step (ie using multiple linqs) but I thought it would look 'clean' using just 1 linq statment.
I have got as far as this:
var names = o.RegisteredNames.Where(d => d.DatabaseName == DBName).Where(d => d.ClientNames.Where(f => f.ClientId == f.Client.ClientId).FirstOrDefault();
But I get the error:
Cannot implicitly convert type 'Services.ClientName' to 'bool'
You have a Problem here:
d => d.ClientNames.Where(f => f.ClientId == f.Client.ClientId)
f => ... returns a single ClientName or null, which causes your error, because there should be a boolean.
If you want this first value or null, you should replace
.Where(d => d.ClientNames ...
//with
.Select(d => d.ClientNames ...
Try this:
o.RegisteredNames.First(d => d.DatabaseName == DBName).ClientNames.Select(x=>x.Client.Subscription.SubscriptionRef)
It should give you list go SubscriptionRef.
You can try with one LINQ query like...
var names = o.RegisteredNames.Where(d => d.DatabaseName == DBName ).FirstOrDefault();
You might wanna try sql style:
var client = from c in db.Clients
join cn in db.ClientNames on c.ClientId equals cn.ClientId
join rn in db.RegisteredNames on cn.RegisteredNamesId equals rn.RegisteredNameId
where rn.DatabaseName == "YourDBName"
select c;
But it also depends on how your objects were built.
Try using join:
var names = (
from names in o.RegisteredNames.Where(d => d.DatabaseName == DBName)
join cnames in o.ClientNames on names.RegisteredNamesId equals cnames.RegisteredNamesId
select cnames.ClientId
).FirstOrDefault();
Add as many joins as you want.
Try this
It works in List,
var option1= o.RegisteredNames
.Where(g => g.DbName == "YourDbName")
.Where(h => h.ClientNames.Any(f => f == 5))
.FirstOrDefault();
var option2= o.RegisteredNames
.FirstOrDefault(h => h.DbName == "Name" && h.ClientNames.Any(j => j == 1));

Linq: GroupBy and Sum

I'm having the hardest time wrapping my mind around LINQ .
I'm querying database
date ColumnC
25-04-2016 10
01-05-2016 8
10-05-2016 4
That I need to Group and Sum by year and month.
I tried to do this but it doesn't work :
public TYPE getX(DateTime value) {
var total = from p in context.table
.Where(p => p.date.Year == value.Year)
group p by p.date.Year into dp
select new
{
result = dp.Sum(s => s.ColumnC),
};
return total;
}
i also could not know the return type.
in other words :
how to get a linq query from this :
select Month(date) Month ,sum(ColumnC) result
from table
group by(Month(date))
==============
Thanks in advance
If you want to have result you have to cast your sum explicitly, therefore losing some data. This is necessary because your initial data is decimal. Therefore the code:
var total = (from p in context.table
.Where(p => p.date.Year == value.Year)
group p by p.date.Month into dp
select new KeyValuePair<int,int> (dp.Key, (int)dp.Sum(s => s.ColumnC))
);
The result of this will be IQueryable<KeyValuePair<int,int>> which is one way to also know the type.
Second option which is more correct would be not to cast the decimal to integer, therefore the code:
var total = (from p in context.table
.Where(p => p.date.Year == value.Year)
group p by p.date.Month into dp
select new KeyValuePair<int,decimal> (dp.Key, dp.Sum(s => s.ColumnC))
);
The result will be IQueryable<KeyValuePair<int,decimal>> which is pretty easy to work with.
In both cases the Key is the Month and the Value is the Sum of ColumnC
Your return type here is partially anonymous, which means you cannot ever know the type.
You can, however, directly retrieve the result as part of the grouping:
public IEnumerable<IGrouping<int, decimal>> getTotalHeures(DateTime value)
{
var total = from p in context.table
.Where(p => p.date.Year == value.Year)
.GroupBy(p => p.date.Month, p => p.ColumnC);
return total;
}

How to retrieve data from table "a" based on different values in table "b"

var c = from p in db.Testings
where p.id == Convert.ToInt32(k)
select new{p.ItemId};`
The above Linq is returning multiple amount of rows containing different ItemIds.
Now, I am trying to retrieve all the rows from Questions table containing all those ItemIds I got returned in the above linq. As expected, the below code is not working. Can anyone please help me with this logic or correct my code if it's a minor logical mistake.
var cfk = from p in db.Questions
where p.ItemId == Convert.ToInt32(c)
select p;
GridView4.DataSource = cfk;
GridView4.DataBind();
Something like:
var cfk = from p in db.Questions
where c.Contains(p.ItemId)
select p;
You can perform an inner join using LINQ.
http://msdn.microsoft.com/en-us/library/bb397941.aspx
I would probably do the join on the Db side during your Get() if possible, though.
Based on your choice of 'cfk' as the second variable name I'm guessing you have setup your database such that Questions.ItemId is a foreign key into Testings, where Testings.ItemId is the primary key of Testings and Testings.id is some other non-key column.
If that is the case you can say:
var cfk = db.Testings
.Where(t => t.id == k)
.SelectMany(t => t.Questions);
or
var cfk = db.Questions
.Where(t => t.Testing.id == k);
If there is no foreign key relationship you would need to do a Join as others suggest e.g.
var cfk = db.Testings
.Where(t => t.id == k)
.Join(db.Questions, t => t.ItemId, q => q.ItemId, (t, q) => q);

Categories