String Format on LINQ controller statement MVC - c#

im having problems using String format on my LINQ but only on my Controller, using it on my view work well, so how can i change my LINQ to not give me an error in the Controller.
This is my LINQ
foreach (var item in db.Pos.Where(r => r.Fecha.Day.ToString() == "2").Select(g => new { Pdv = g.Pdv, Total = g.Total })
.GroupBy(l => l.Pdv).Select(z => new { Pdv = z.Key, Total = String.Format("{0:$#,##0.00;($#,##0.00);Zero}",Decimal.Round(z.Sum(l => l.Total), 0) }))
{
listadepuntos.Add(item.ToString());
}
var grupoPdv = new SelectList(listadepuntos.ToList());
ViewBag.GroupS = grupoPdv;
what i want is that the data of ViewBag.GroupS gets ',' each 3 digits , like for hundreds, thousands and millions right now i get the date plain without format.
what can i do?

You can call AsEnumerable extension method after your group by to execute your Select method using Linq to Objects instead Linq to Entities:
.GroupBy(l => l.Pdv)
.AsEnumerable()// Add this
.Select(z => new { Pdv = z.Key, Total = String.Format("{0:$#,##0.00;($#,##0.00);Zero}",Decimal.Round(z.Sum(l => l.Total), 0) })
The issue is because your Linq provider doesn't know how to convert your method calls to a proper expression tree, which later need to be translated to a SQL statement. There is a few string methods that are currently supported (you will find them in this link), String.Format is not one of them. In case of Decimal.Round which is either supported, you could use System.Math.Round instead.

Related

Linq statement with Projection to class THEN GroupBy results in local evaluation

I'm sending an IQueryable to a method that parses data for jQuery DataTables. It builds the filter from FORM data and creates a LINQ statement with filter, sorting, paging, etc that gets sent back to the page as JSON. I'd like to extend the parser and add Totals to the result set. When I add a GroupBy statement, the query is not evaluated on the server, but locally instead. It will only execute on the server if the original IQueryable has an anonymous projection...
This is a .Net Core 2.1 website. I know in the past GroupBy could not be executed locally but it does at 2.1. I've tried projection with a class and to an anonymous type, and it only works properly with an anonymous type. I really need to be able to do this with a class.
The following iQueryable gets sent to the parser:
var query = Context.InvoiceHeaders
.AsNoTracking()
.Where(x=>x.Slsno.Equals("13"))
.Select(x => new InvoiceHeaderSummary()
{
SalesNumber = x.Slsno,
OrderNumber = x.Ordnum,
ItemAmount = x.Itmamt,
SpecialChargeAmount = x.Sc1amt,
TaxAmount = x.Taxamt,
InvoiceTotal = x.Invamt
})
var parser = new Parser<InvoiceHeaderSummary>(Request.Form, query);
I'm trying to extend the parser by adding a List of totals to the output. But since I'm sending in an IQueryable with a class projection (InvoiceHeaderSummary), it doesn't execute on the server. I get the warning about it being evaluated locally:
var totalList = query
.GroupBy(i => 1)
.Select(g => new
{
TotalInvoice = g.Sum(i => i.InvoiceTotal)
})
.ToList();
I tried creating the entire LINQ method inline and it DOES run properly (notice I'm using an anonymous projection prior to the GroupBy rather than InvoiceHeaderSummary class):
var query = Context.InvoiceHeaders
.AsNoTracking()
.Where(x=>x.Slsno.Equals("13"))
.Select(x => new
{
SalesNumber = x.Slsno,
OrderNumber = x.Ordnum,
ItemAmount = x.Itmamt,
SpecialChargeAmount = x.Sc1amt,
TaxAmount = x.Taxamt,
InvoiceTotal = x.Invamt
})
.GroupBy(i => 1)
.Select(g => new
{
TotalInvoice = g.Sum(i => i.InvoiceTotal)
})
.ToList();
Is there a way to properly write this so it runs optimally??
Apparently one of the EF Core 2.x query translation defects / bugs.
The only workaround I've found is to use the GroupBy overload with element selector and select the data you want to aggregate into anonymous type:
var totalList = query
.GroupBy(i => 1, i => new { i.InvoiceTotal }) // <--
.Select(g => new
{
TotalInvoice = g.Sum(i => i.InvoiceTotal)
})
.ToList();

Group By struct list on multiple columns in C#

I am having a struct as
public struct structMailJob
{
public string ID;
public string MailID;
public int ResendCount;
public int PageCount;
}
and a list as
List<structMailJob> myStructList = new List<structMailJob>();
I have loaded data in myStructList from database and want myStructList data in a new list after grouping by MailID and ResendCount.
I am trying as:
List<structMailJob> newStructList = new List<structMailJob>();
newStructList = myStructList.GroupBy(u => u.MailID, u=>u.ResendCount)
.Select(grp => new { myStructList = grp.ToList() })
.ToList();
but unable to do that as getting error message - cant implicitly convert generic list to structMailJob.
I think that you are looking for is the following:
var newStructList = myStructList.GroupBy(smj => new { smj.MailID, smj.ResendCount })
.Select(grp => new
{
MailID = grp.Key.MailID,
ResendCount = grp.Key.ResendCount
MailJobs = grp.Select(x=>new
{
x.ID,
x.PageCount
}).ToList()
})
.ToList();
Note that we changed the GroupBy clause to the following one:
GroupBy(smj => new { smj.MailID, smj.ResendCount })
Doing so, the key on which the groups would be created would be consisted of both MailID and ResendCount. By the way the former GroupBy clause isn't correct.
Then having done the grouping, we project each group to an object with three properties, MailID and ResendCout, which are the components of the key and list of anonymous type object with two properties, ID and PageCount, which we gave it the name MailJobs.
Last but not least you will notice that I didn't mention the following
List<structMailJob> newStructList = new List<structMailJob>();
I just used the var and declared the newStructList. I don't think that you stated in your post makes sense. How do we expect to get a list of the same objects after grouping them? So I assumed that you might want is the above.
However, I thought you might want also something like this and you didn't want to refer to Grouping.
myStructList = myStructList.OrderBy(smj => smj.MailID)
.ThenBy(smj => smj.ResendCount)
.ToList();
Linq Query is completely incorrect, following are the important points:
myStructList.GroupBy(u => u.MailID, u=>u.ResendCount) // Incorrect grouping
myStructList.GroupBy(u => new {u.MailID, u.ResendCount }) // Correct grouping, which will do by two columns MailID and ResendCount, last one was only doing by MailID and was using ResendCount for result projection
Now the result is of type IEnumerable<IGrouping<AnonymousType,structMailJob>>, so when you do something like Select, it will end up creating Concatenated List of type IEnumerable<List<structMailJob>> (Removed the assignment to myStructList inside the Select, as that was not correct):
.Select(grp => grp.ToList())
Correct code would require you to flatten using SelectMany as follows:
newStructList = myStructList.GroupBy(u => new {u.MailID, u.ResendCount})
.SelectMany(grp => grp.ToList()).ToList();
Assign it to newStructList, but this code has little use, since literally newStructList is exactly same as myStructList post flattening, ideally you shall be able to use the grouping, so that you can get a subset and thus the correct result, however that depends on your business logic
I don't know if I got your question right but it seems to me you missed the 'Group by' signature.
List<structMailJob> myStructList = new List<structMailJob>();
List<structMailJob> newStructList = new List<structMailJob>();
newStructList = myStructList
// .GroupBy(/*Key Selector */u => u.MailID, /*Element Selector*/u=>u.ResendCount)
.GroupBy(u => new { u.MailID, u.ResendCount }) // broup by MailID, ResendCount
// Note no Element Selector , the 'STRUCT' is 'SELECTED'
.Select(grp => {
// NOte: Key == Anonymous {MailID, ResendCount }
return grp;
})
// otherwise you get a IEnumerable<IEnumerable<T>> instead of IEnumerable<T> because you grouped it
.SelectMany(x=>x)
.ToList();
If Mrinal Kamboj's answer is what you are looking for, then you could use the following as an alternative:
var orderedList = myStructList.OrderBy(x => x.MailID).ThenBy(x => x.ResendCount);

Refactor Linq query

I am trying to cut this linq down
var sys = db.tlkpSystems
.Where(a => db.tlkpSettings.Where(e => e.Hidden < 3)
.Select(o => o.System)
.ToList().Contains(a.System)) //cannot get this part in?
.OrderBy(a => a.SystemName).ToList();
foreach (var item in sys)
model.Add(new SettingSystem {
System = item.System,
SystemName = item.SystemName
});
I have tried the following:
List<SettingSystem> model = new List<SettingSystem>();
model = db.tlkpSettings.Where(e => e.Hidden < 3)
.OrderBy(e => e.Setting)
.Select(e => new SettingSystem
{
System = e.System,
SystemName = e.Setting
}).ToList();
How can I call the .Contains(a.System) part in my query?
Thanks
Some general rules when working with LINQ to Entities:
Avoid using ToList inside the query. It prevents EF to build a correct SQL query.
Don't use Contains when working with entities (tables). Use Any or joins.
Here is your query (in case System is not an entity navigation property):
var sys = db.tlkpSystems
.Where(a => db.tlkpSettings.Any(e => e.Hidden < 3 && e.System == a.System))
.OrderBy(a => a.SystemName).ToList();
As an addendum, there is also AsEnumerable for when you must pull a query into memory (such as calling methods within another clause). This is generally better than ToList or ToArray since it'll enumerate the query, rather than enumerating, putting together a List/Array, and then enumerating that collection.

Linq using Distinct() in C# Lambda Expression

SFC.OrderFormModifiedMonitoringRecords
.SelectMany(q => q.TimeModify, w => w.DateModify)
.Distinct()
.OrderBy(t => t)
.SelectMany(t => new { RowID = t.rowID, OFnum = t.OFNo });
It's Error did i missed something or is it Completely Coded The Wrong Way? After this i'm gonna use this on a Foreach method to gather up multiple data without the duplicates.
The delegate you pass to SelectMany must return an IEnumerable and is for collapsing multiple collections into one. So yes, something's definitely wrong here. I think you've confused it with Select which simply maps one collection to another.
Without knowing what your goal is, it's hard to know exactly how to fix it, but I'm guessing you want something like this:
SFC.OrderFormModifiedMonitoringRecords
.OrderBy(t => t.DateModify)
.ThenBy(t => t.TimeModify)
.Select(t => new { RowID = t.rowID, OFnum = t.OFNo })
.Distinct();
Or in query syntax:
(from t in SFC.OrderFormModifiedMonitoringRecords
orderby t.DateModify, t.TimeModify
select new { RowID = t.rowID, OFnum = t.OFNo })
.Distinct();
This will order the records by DateModify then by TimeModify, select two properties, rowID and OFNo and return only distinct pairs of values.

Only parameterless constructors and initializers are supported in LINQ to Entities message

I have a method that returns data from an EF model.
I'm getting the above message, but I can't wotk our how to circumvent the problem.
public static IEnumerable<FundedCount> GetFundedCount()
{
var today = DateTime.Now;
var daysInMonth = DateTime.DaysInMonth(today.Year, today.Month);
var day1 = DateTime.Now.AddDays(-1);
var day31 = DateTime.Now.AddDays(-31);
using (var uow = new UnitOfWork(ConnectionString.PaydayLenders))
{
var r = new Repository<MatchHistory>(uow.Context);
return r.Find()
.Where(x =>
x.AppliedOn >= day1 && x.AppliedOn <= day31 &&
x.ResultTypeId == (int)MatchResultType.Accepted)
.GroupBy(x => new { x.BuyerId, x.AppliedOn })
.Select(x => new FundedCount(
x.Key.BuyerId,
x.Count() / 30 * daysInMonth))
.ToList();
}
}
FundedCount is not an EF enity, MatchHistory is, so can't understand why it is complaining.
All advice appreciated.
The reason it is complaining is because it doesn't know how to translate your Select() into a SQL expression. If you need to do a data transformation to a POCO that is not an entity, you should first get the relevant data from EF and then transform it to the POCO.
In your case it should be as simple as calling ToList() earlier:
return r.Find()
.Where(x => x.AppliedOn >= day1 && x.AppliedOn <= day31 &&
x.ResultTypeId == (int)MatchResultType.Accepted)
.GroupBy(x => new { x.BuyerId, x.AppliedOn })
.ToList() // this causes the query to execute
.Select(x => new FundedCount(x.Key.BuyerId, x.Count() / 30 * daysInMonth));
Be careful with this, though, and make sure that you're limiting the size of the data set returned by ToList() as much as possible so that you're not trying to load an entire table into memory.
Message is clear : linq to entities doesn't support objects without a parameterless ctor.
So
Solution1
enumerate before (or use an intermediate anonymous type and enumerate on that one)
.ToList()
.Select(x => new FundedCount(
x.Key.BuyerId,
x.Count() / 30 * daysInMonth))
.ToList();
Solution2
add a parameterless ctor to your FundedCount class (if it's possible)
public FundedCount() {}
and use
.Select(x => new FundedCount{
<Property1> = x.Key.BuyerId,
<Property2> = x.Count() / 30 * daysInMonth
})
.ToList();
It's complaining because it can't convert references to FundedCount to SQL statements.
All LINQ providers convert LINQ statements and expressions to operations that their target can understand. LINQ to SQL and LINQ to EF will convert LINQ to SQL, PLINQ will convert it to Tasks and parallel operations, LINQ to Sharepoint will convert it to CAML etc.
What happens if they can't do the conversion, depends on the provider. Some providers will return intermediate results and convert the rest of the query to a LINQ to Objects query. Others will simply fail with an error message.
Failing with a message is actually a better option when talking to a database. Otherwise the server would have to return all columns to the client when only 1 or 2 would be actually necessary.
In your case you should modify your select to return an anonymous type with the data you want, call ToList() and THEN create the FundedCount objects, eg:
.Select( x=> new {Id=x.Key.BuyerId,Count=x.Count()/30 * daysInMonth)
.ToList()
.Select(y => new FundedCount(y.Id,y.Count))
.ToList();
The first ToList() will force the generation of the SQL statement and execute the query that will return only the data you need. The rest of the query is actually Linq to Objects and will get the data and create the final objects
I had the same exception in GroupBy. I found that the exception "Only parameterless constructors and initializers are supported in LINQ to Entities" is not 100% accurate description.
I had a GroupBy() in my "Linq to EntityFramework query" which used a struct as a Key in GroupBy. That did not work. When I changed that struct to normal class everything worked fine.
Code sample
var affectedRegistrationsGrouped = await db.Registrations
.Include(r => r.Person)
.Where(r =>
//whatever
)
.GroupBy(r => new GroupByKey
{
EventId = r.EventId,
SportId = r.SportId.Value
})
.ToListAsync();
...
...
// this does not work
private struct GroupByKey() {...}
// this works fine
private class GroupByKey() {...}

Categories

Resources