Unknown column GroupBy1.K1 in field list - c#

First off, this worked with MSSQL Server but we've switched over to MySQL and now it isn't working.
I have a simple query which returns total values based off a certain year.
It looks like this:
public Dictionary<string, decimal> GetYearValues(int[] SupplierID) {
_ctx.Database.CommandTimeout = 5 * 60;
var Total = (from x in _ctx.Invoices
where x.Turnover == true &&
SupplierID.Contains(x.FK_SupplierID)
group x by new { x.InvoiceDate.Year } into summ
select new {
Year = summ.Key.Year,
TurnOver = summ.Sum(s => s.NetAmount_Home ?? 0)
}).ToDictionary(x => x.Year.ToString(), x => x.TurnOver);
return Total;
}
I've noticed that nothing is wrong with the query, it's only the ToDictionary which fails and gives the error message. Can anyone tell me why?

Related

Lambda Sum subquery not giving the right result

I have an IQueryable that should be able to sum the points of all records in a subquery like so (This is meant to work with OData):
public Task<IQueryable<TemplatePMPResultViewModel>> GetTemplatePMPResultViewModel()
{
var result = _dbSet.Select(x => new TemplatePMPResultViewModel
{
Id = x.Id,
InsertDate = x.InsertDate,
Latitude = x.Latitude,
Longitude = x.Longitude,
CompanyAssetName = x.TemplatePMP.CompanyAsset.CodeAsset,
ConstructionSiteName = x.ConstructionSite.Name,
MechanicName = x.Mechanic.Name,
SupervisorName = x.Supervisor.Name,
Points = _dbContext.ItemCheckListResults.Where(x => x.TemplatePMPResultId.Equals(x.Id)).Sum(x => x.Points),
PendingPoints = _dbContext.ItemCheckListResults
.Where(x => x.TemplatePMPResultId.Equals(x.Id) &&
x.ExecuteActionPlan &&
(x.EndDate ?? DateTime.MaxValue) <= DateTime.Now)
.Sum(x => x.Points),
RegionName = x.ConstructionSite.Region.Name,
TypeName = x.TemplatePMP.CompanyAsset.Group.GroupType.Description
});
return Task.FromResult(result);
}
However the sum of points is returning the wrong value, when I get the query from the output window and execute it in my database manager query tool it works just fine. (I just change the Id of the record I want to see)
From what I cant tell, the lambda expression returns only the sum of the first record of ItemCheckListResults but not the sum of all records.
Can I run subqueries like that or should I try another aproach, if so, how should I do it?
Best regards!

Why MAX is not working with where in Entity Framework?

I am new to EF and writing this to select then max record that contains the combination. Now i want to pick MAX of those records only.
public string GetMaxReportNo(string OfficeStationCombination = "")
{
InspectionReport InspectionReport= new InspectionReport();
string VelosiReportNo="";
var query = uow.InspectionReportRepository.GetQueryable().AsQueryable();
if (!string.IsNullOrEmpty(OfficeStationCombination))
{
VelosiReportNo = (string)query
.Where(x => x.VelosiReportNo.Contains(OfficeStationCombination))
.FirstOrDefault().VelosiReportNo.ToString();
}
return VelosiReportNo;
}
I tried everything to pick the max InspectionReportID record in where but nothing works
Order by the specified column (inspectionReportID) descendingly then take the first record:
VelosiReportNo = (string)query
.Where(x => x.VelosiReportNo.Contains(OfficeStationCombination))
.OrderByDesc(x => x.inspectionReportID)
.FirstOrDefault().VelosiReportNo.ToString();

How can I fill the gaps in attribute values in the list?

I have a list:
List<BtnCountViews> btnCountViewsList;
The BtnCountViews class looks like this:
public class BtnCountViews
{
public int DayOfYear { get; set; }
public int BtnCount { get; set; }
public int Views { get; set; }
}
I have a rather unusual requirement and I am not sure how to go about starting to implement it.
What I would like to do is to fill in the btnCountViewsList with `BtnCountViews for the missing DayOfYear with objects that have a BtnCount of 0 and Views of 0.
To give me a start can anyone tell me how I can find the min and max DayOfYear in the btnCountViewsList. Note I tagged this with LINQ but I'm not sure if this is the best tool to use.
Also would be happy if someone can suggest a way to fill in the missing objects but that's not really the focus of this question as I think I need to find out how to get the min and max first.
You can add missing days without finding min and max explicitly:
Sort the list by DayOfYear in ascending order (how?)
Start a loop index i at the end of the list, and work your way backward; stop when i reaches zero
Compare DayOfYear attribute at i and i-1
If the two days differ by one, move down to the next i
Otherwise insert a new record with DayOfYear set to that of btnCountViewsList[i] minus one.
At the end of this process your list would contain entries for each value of DayOfYear. Here is a sample implementation:
items.Sort((x, y) => x.DayOfYear.CompareTo(y.DayOfYear));
Console.WriteLine("Before: {0}", string.Join(", ", items.Select(x => x.DayOfYear)));
int i = items.Count-1;
while (i > 0) {
if (items[i].DayOfYear == items[i-1].DayOfYear+1) {
i--;
} else {
items.Insert(i, new BtnCountViews { DayOfYear = items[i].DayOfYear-1 });
}
}
Demo.
This is working on linqpad:
Int32 max = 0, min = 0;
btnCountViewsList.ForEach(x => {
min = Math.Min(x.Views, min);
max = Math.Max(x.Views, max);
});
What I would like to do is to fill in the btnCountViewsList with `BtnCountViews for the missing DayOfYear with objects that have a BtnCount of 0 and Views of 0.
My suggestion is that we don't try to find the missing days, we create all:
BtnCountViews[] arr = new BtnCountViews[365]; // or 366?
// suppose DayOfYear begins with 0.
for (int i = 0; i < arr.Length; i++)
{
arr[i] = new BtnCountViews { DayOfYear = i };
}
foreach (BtnCountViews item in btnCountViewsList)
{
arr[item.DayOfYear].BtnCount = item.BtnCount;
arr[item.DayOfYear].Views = item.Views;
}
then arr is what you want.
And if the result should be the btnCountViewsList:
btnCountViewsList.Clear();
btnCountViewsList.AddRange(arr);
So the lazy in me says, make a backfill list and use your existing (and gappy) list as a map.
public static IList<BtnCountViews> GetDefaultList()
{
var defaultList = Enumerable.Range(1, 365).Select(e =>
new BtnCountViews
{
DayOfYear = e,
BtnCount = 0,
Views = 0
}
).ToList();
return defaultList;
}
Iterate through the backfill list and consult the map to see if the DayOfYear value exists as a key, and if not, then add it to the map.
public static IList<BtnCountViews> GetBackFilledList(IList<BtnCountViews> incoming)
{
var map = incoming.ToDictionary(k => k.DayOfYear, v => v);
var defaultList = GetDefaultList();
foreach(var itm in defaultList)
{
if (map.ContainsKey(itm.DayOfYear)) continue;
map.Add(itm.DayOfYear, itm);
}
return map.Select(m => m.Value).ToList();
}
Once the iteration is finished, convert the map into a list, which should now consist of the original values + default values for missing DayOfYear entries as well.
return map.Select(m => m.Value).ToList();
Dotnetfiddle of a sample program here: https://dotnetfiddle.net/wSJy56
Is there a more elegant way to do this? Most surely. But this code executes in about 0.011 seconds, which to me is pretty decent so long as you're not calling this functionality over and over again (e.g. you decide to analyze 30 years of data and need to get that done in 0.011 seconds). But then we'd have to be looking more towards parallelism rather than code elegance to solve that can of worms.
Hope this helps...
Try the following
btnCountViewsList = btnCountViewsList.Where(b => b.BtnCount == 0).Where(v => v.Views == 0).ToList();
If I understood what you were asking, you want to get objects where BtnCount = 0 and Views = 0.
This will select all the objects where Views = 0, and then that IEnumarable will be through another LINQ expression where it only selects the other property that equals to 0.
The shortest linq way, using an left outer join (LEFT OUTER JOIN in LINQ) and Range
var result = (from a in Enumerable.Range(0, 365)
join lst in btnCountViewsList on a equals lst.DayOfYear into ps
from p in ps.DefaultIfEmpty()
select (p==null) ? new BtnCountViews() { DayOfYear = a}:p).ToList()
among the lines of some other responses, but without hard coding the total days of the year as leap years will have 366 days
var range = new
{
Start = new DateTime(2017, 1, 1),
End = new DateTime(2017, 12, 31),
};
var days = Enumerable.Range(range.Start.DayOfYear, range.End.DayOfYear);
var query = from day in days
from counter in
(
from temp in btnCountViewsList
where temp.DayOfYear == day
select temp
).DefaultIfEmpty()
select new BtnCountViews
{
DayOfYear = day,
BtnCount = counter == null ? 0 : counter.BtnCount,
Views = counter == null ? 0 : counter.Views,
};
will give you something like

Linq sum by variable number of monthS or weekS

SqlServer table contains records of time and hours burned, materials cost by vendors
[IdPK] [DateTime] [MaterialsCost] [Hours] [Vendor_FK] [Project_FK] [Lat] [Long]
The user decides how far back he wants to see totals and for which column value, i.e. he wants totals going back - X number of monthS, or X number of weekS on any columns_FK filter value.
For e.g. he wants totals for cost, hours on either, Vendor = Nike or ProjectX, going back (1) month, (3) weeks, or 2 months from a certain date. So, I'm trying to get the totals for based on a parameterized Linq query.
Question:
Using any of columns as a filter/selector in linq, how to get the Monthly/weekly totals for cost,hours - going back (X) number of months or weeks?
Also, should I write separate queries for months vs weeks, and separate queries for each column (columns value selected by the user, is passed to me as a genric val)?
// I tried this... but just stuck
DateTime now = DateTime.Now;
Int goBack = passedinGoingBack; // amount of units to go back
var backUnits = obj.GetType().GetProperty(name); // tried getting month or week??
var getRows = table.AsEnumerable()
var columnName = passedInColumnName;
var filter = passedInValue;
.Where(r => r.Field<DateTime>(columnName).Year == now.Year
&& r.Field<DateTime>(columnName).Month == now.Month);
This question is a little bit opinion-based. You can do it in any way it is convenient for you. That's how I would do this.
First: you can use Sum LINQ function for getting total according to the given summing rule.
var monthlyRows = table.AsEnumerable()
.Where(r => r.Field<DateTime>("ColumnName").Year == now.Year
&& r.Field<DateTime>("ColumnName").Month == now.Month);
var monthlyTotalForCost = monthlyRows.Sum(r => r.Field<decimal>("CostColumn"));
var monthlyTotalForHours = monthlyRows.Sum(r => r.Field<decimal>("HoursColumn"));
var weeklyRows = table.AsEnumerable()
.Where(r => r.Field<DateTime>("ColumnName").Year == now.Year
&& r.Field<DateTime>("ColumnName").Week == now.Week);
var weeklyTotalForCost = monthlyRows.Sum(r => r.Field<decimal>("CostColumn"));
var weeklyTotalForHours = monthlyRows.Sum(r => r.Field<decimal>("HoursColumn"));
Second: I would do separate queries for weekly and monthly totals as that' a sum of different entity values and there can be a different logic.
However, I would do a helping function for me like this:
public static class TableLinqHelper
{
public static SumOfTableColumn<T>(this IEnumerable<DataRow> rows, string columnName)
{
return rows.Sum(r => r.Field<T>(columnName));
}
public static DateTime GetDate(this DataRow row)
{
return row.Field<DateTime>("DateColumn");
}
public static GetTotalForCost(this IEnumerable<DataRow> row)
{
return SumOfTableColumn<decimal>(row, "CostColumn");
}
public static GetTotalForHours(this IEnumerable<DataRow> row)
{
return SumOfTableColumn<double>(row, "HoursColumn");
}
}
var monthlyRows = table.AsEnumerable()
.Where(r => r.GetTime().Year == now.Year
&& r.GetTime().Month == now.Month);
var weeklyRows = table.AsEnumerable()
.Where(r => r.GetTime().Year == now.Year
&& r.GetTime().Week == now.Week);
var monthlyTotalForCost = monthlyRows.GetTotalForCost();
var monthlyTotalForHours = monthlyRows.GetTotalForHours();
var weeklyTotalForCost = weeklyRows.GetTotalForCost();
var weeklyTotalForHours = weeklyRows.GetTotalForHours();
Update:
Filtering: You can filter your results using Where LINQ.
Dictionary<string, object> Filters = new Dictionary<string, object>();
Filters.Add("VendorColumn", "Nike");
Filters.Add("Hours", 7.0);
foreach (var filter in Filters)
{
monthlyRows = monthlyRows.Where(r => // ...);
}
Several monthes and weeks: You can change the condition of DateTime where.
int rowsToBeShown = 4;
var monthlyRows = table.AsEnumerable()
.Where(r => r.Field<DateTime>("ColumnName") > DateTime.Now.AddMonths(-rowsToBeShown));
It will show results for the last 4 monthes.
LINQ provides very convenient and flexible tools for data manipulation. It's all up to your fantasy.

Get position of a specific id in an order by query

I need to do a query in c# to get the position of a specific id, in a table order by a date.
My table structure
IdAirport bigint
IdUser int
AddedDate datetime
Data:
2 5126 2014-10-23 14:54:32.677
2 5127 2014-10-23 14:55:32.677
1 5128 2014-10-23 14:56:32.677
2 5129 2014-10-23 14:57:32.677
For example, i need to know in which position is the IdUser=5129, in the IdAirport=2, order by AddedDate asc. (The result in this case will be 3).
Edit:
im using iQueryables like this:
AirPort airport = (for airport as context.Airport select airport).FirstOrDefault();
Thanks for your time!
Using LINQ: If you want to find the index of an element within an arbitrary order you can use OrderBy(), TakeWhile() and Count().
db.records.Where(x => x.IdAirport == airportId)
.OrderBy(x => x.AddedDate)
.TakeWhile(x => x.IdUser != userId)
.Count() + 1;
Here's a quick one :
public class test
{
public int IdAirport;
public int IdUser;
public DateTime AddedDate;
public test(int IdAirport, int IdUser, DateTime AddedDate)
{
this.IdAirport = IdAirport;
this.IdUser = IdUser;
this.AddedDate = AddedDate;
}
}
void Main()
{
List<test> tests = new List<test>()
{
new test(2, 5126, DateTime.Parse("2014-10-23 14:54:32.677")),
new test(2, 5127, DateTime.Parse("2014-10-23 14:55:32.677")),
new test(1 , 5128 , DateTime.Parse("2014-10-23 14:56:32.677")),
new test(2 , 5129 , DateTime.Parse("2014-10-23 14:57:32.677"))
};
var r = tests
.Where(t => t.IdAirport == 2)
.OrderBy(t => t.AddedDate)
.TakeWhile(t => t.IdUser != 5129)
.Count() + 1;
Console.WriteLine(r);
}
It keeps the exact order of your own list. You can modify Where/OrderBy if you wish, the interesting part is in the "TakeWhile/Count" use.
Should work fine but probably not very efficient for long lists.
edit : seems to be the same as Ian Mercer. But the "+ 1" in my own sample is needed since TakeWhile will return the number of skipped items, hence not the position of the good one. Or I didn't get well the issue.
This should do what you need:
dataTable.Rows.IndexOf(
dataTable.AsEnumerable().OrderBy(
x => x["AddedDateColumn"]).First(
x => (int)(x["IdUserColumn"]) == 5129));

Categories

Resources