Linq merging two classes into a third? - c#

I am trying to merge 2 classes into a third on the date properties, for binding to a graph I have already setup.
public class Last30DaysHours
{
public DateTime Date { get; set; }
public float Hours { get; set; }
public float LostHours { get; set; }
}
public class MachineHours
{
public DateTime Date { get; set; }
public float Hours { get; set; }
}
into
public class GraphLast30Days
{
public DateTime Date { get; set; }
public float Hours { get; set; }
public float LostHours { get; set; }
public float SelectedMachine { get; set; }
}
So far I have this linq statement which almost compiles.
The error with the current statment is "'x' does not exist in the current context".
I know what this means but I don't know how to make it accessable in the statement.
IEnumerable<GraphLast30Days> last30DaysMachineHoursSelect = _last30DaysMachineHours
.Select(p => (_last30Days
.Where(x => x.Date == p.Date) <=
(new GraphLast30Days {
Date = x.Date,
Hours = x.Hours,
LostHours = x.LostHours,
SelectedMachine = p.Hours
})));
My question is how do I make x accessable by the second half of the statement or what is a better statement to achieve the same results?
Thanks for the help.

You'd wont to use join to join your collections by date (not sure I got the correct proeprties, but you got the idea):
IEnumerable<GraphLast30Days> last30DaysMachineHoursSelect =
from machineHours in _last30DaysMachineHours
join last30 in _last30Days on machineHours.Date equals last30.Date
select
new GraphLast30Days {
Date = machineHours.Date,
Hours = machineHours.Hours,
LostHours = last30.LostHours,
SelectedMachine = machineHours.Hours
};
Or with alternative syntax:
var result = _last30DaysMachineHours.Join(_last30Days, graph => graph.Date, last30 => last30.Date,
(graph, last30) => new GraphLast30Days
{
Date = graph.Date,
Hours = graph.Hours,
LostHours = last30.LostHours,
SelectedMachine = graph.Hours
});
In case you don't wont to filter out missing values you'll need to do left join:
IEnumerable<GraphLast30Days> last30DaysMachineHoursSelect =
from last30 in _last30Days
from machineHours in _last30DaysMachineHours.Where (h => h.Date == last30.Date).DefaultIfEmpty()
select
new GraphLast30Days {
Date = last30.Date,
Hours = last30.Hours,
LostHours = last30.LostHours,
SelectedMachine = machineHours == null ? 0 : machineHours.Hours
}

Related

Conversion of this SQL Query to LINQ

SELECT
CreationUtcTime, Speed,
CONVERT(varchar, (CreationUtcTime - LAG(CreationUtcTime) OVER (ORDER BY CreationUtcTime)), 108) AS diff
FROM
assetstatusrecords
WHERE
Speed <> 0.00
ORDER BY
CreationUtcTime
I want this SQL query to be converted to LINQ query without using LINQTODB functions and I want exact difference including hours, days, seconds, minutes such that I want to sum the time at later stage.
What I have tried is below:
var records = _context.AssetStatusRecords
.OrderByDescending(s => s.CreationUtcTime)
.Where(s => s.AssetId.Equals(asset.Id)
&& s.CreationUtcTime >= from
&& s.CreationUtcTime <= to
&& s.Speed != 0)
.ToList();
var query = from rec1 in records
from rec2 in records.Where(r => rec1.SequentialId > r.SequentialId).DefaultIfEmpty()
group new { rec1, rec2 } by new { rec1.SequentialId, rec1.CreationUtcTime, rec1.Speed } into g
orderby g.Key.SequentialId
select new
{
g.Key.CreationUtcTime,
g.Key.Speed,
Diff = EntityFunctions.DiffDays(g.Max(p => p.rec2.CreationUtcTime), g.Key.CreationUtcTime)
};
Model class for LINQ
class AssetStatusRecord : Entity
{
protected AssetStatusRecord()
{
}
public AssetStatusRecord(CoordinatesValue coordinates, double speed,
LengthValue distanceTravelled, Guid sensorId, Guid? assetId,
int? heading, Guid readingId, DateTime? sensorDateTime)
{
Coordinates = coordinates;
Speed = speed;
DistanceTravelled = distanceTravelled;
SensorId = sensorId;
AssetId = assetId;
Heading = heading;
ReadingId = readingId;
SensorDateTime = sensorDateTime;
}
public CoordinatesValue Coordinates { get; private set; }
public double Speed { get; private set; }
public LengthValue DistanceTravelled { get; private set; }
public Guid SensorId { get; private set; }
public Guid? AssetId { get; private set; }
public int? Heading { get; private set; }
public Guid ReadingId { get; private set; }
public DateTime? SensorDateTime { get; private set; }
}
And the Entity class is as follows:
public class Entity : IEntity
{
public Entity();
public Guid Id { get; protected set; }
public long SequentialId { get; protected set; }
public DateTime CreationUtcTime { get; protected set; }
public DateTime CreationLocalTime { get; protected set; }
}
And this is the interface IEntity:
public interface IEntity
{
Guid Id { get; }
long SequentialId { get; }
DateTime CreationUtcTime { get; }
}
Try the following query:
var records = _context.AssetStatusRecords
.Where(s => s.AssetId == asset.Id
&& s.CreationUtcTime >= from
&& s.CreationUtcTime <= to
&& s.Speed != 0);
var query =
from current in records
from prev in records
.Where(prev => current.CreationUtcTime <= prev.CreationUtcTime && prev.SequentialId < current.SequentialId)
.OrderByDescending(prev => prev.CreationUtcTime)
.Take(1)
.DefaultIfEmpty()
orderby current.CreationUtcTime
select new
{
current.CreationUtcTime,
current.Speed,
Diff = EntityFunctions.DiffDays(current.CreationUtcTime, prev.CreationUtcTime)
};

I want to modify the data in my object using Linq

var todate = Filters.Where(it => it.Value == "ApplicationDateToSearch").Select(it =>
{
if (DateTime.TryParse(it.Description, out DateTime ConvertedToDate))
{
it.Description = ConvertedToDate.AddHours(23).AddMinutes(59).AddSeconds(59).ToString();
}
})?.FirstOrDefault();
Visual Studio doesn't seem to like this.
List<EmployeeRole> Filters
public class EmployeeRole
{
public String Description { get; set; }
public String Value { get; set; }
public int IntValue { get; set; }
}
The 'select' statement is used to select the properties you can't modify in that, so you have to use the 'ForEach' statement for that. But 'ForEach' statement doesn't have any return type so after that you can use FirstOrDefault
var x = Filters.Where(i => i.Value == "ApplicationDateToSearch").ToList();
x.ForEach(i => i.Description = DateTime.TryParse(i.Description, out DateTime ConvertedToDate) ? ConvertedToDate.AddHours(23).AddMinutes(59).AddSeconds(59).ToString() : string.Empty);
var todate = x.FirstOrDefault();

Group By query in mvc5

Hi i want to write sql Group by query in C# of my MVC5 application.
In the above image I have group by query which i wrote in sql . That I want to write in C# front end.
I tried to write query in front end. But I am getting error which is mentioned in the image. Now I want to write that Group By query in C# and want to display the each employee with count (output same as mentioned in the first image). Can anyone help me to resolve this issue?
My ViewModel(Dashnboard View model)
public class DashboardViewmodel
{
public List<CustomerTypeCountModel> CustomerTypesCountModels { get; set; }
public List<View_VisitorsForm> Visits { get; set; }
public CustomerTypeViewModel CustomerTypeViewModels { get; set; }
public int sizingcount { get; set; }
public int Processingcount { get; set; }
//here i declared two properties
public string EmployeeName { get; set; }
public string EmployeeCount { get; set; }
}
My Controller code
[HttpGet]
public ActionResult SalesVisit()
{
return View();
}
public ActionResult GetDatesFromSalesVisit(DashboardViewmodel dvm)
{
var fromdate = Convert.ToDateTime(dvm.CustomerTypeViewModels.FromDate);
var todate = Convert.ToDateTime(dvm.CustomerTypeViewModels.ToDate);
List<View_VisitorsForm> empcount = new List<View_VisitorsForm>();
if (DepartmentID == new Guid("47D2C992-1CB6-44AA-91CA-6AA3C338447E") &&
(UserTypeID == new Guid("106D02CC-7DC2-42BF-AC6F-D683ADDC1824") ||
(UserTypeID == new Guid("B3728982-0016-4562-BF73-E9B8B99BD501"))))
{
var empcountresult = db.View_VisitorsForm.GroupBy(G => G.Employee)
.Select(e => new
{
employee = e.Key,
count = e.Count()
}).ToList();
empcount = empcountresult ;//this line i am getting error
}
DashboardViewmodel obj = new DashboardViewmodel();
return View("SalesVisit", obj);
}
When you use a GroupBy you get an IEnumerable<IGrouping<Key,YourOriginalType>> so you do not have .Employee and .VisitingID properties.
Change as following:
public class EmployeeCount
{
public string Employee {get; set;}
public int Count {get; set;}
}
List<EmployeeCount> result = db.View_VisitorsForm
.Where(item => item.VisitingDate >= beginDate && item.VisitingDate < endDate)
.GroupBy(G => G.Employee)
.Select(e =>new EmployeeCount
{
employee = e.Key,
count = e.Count()
}).ToList();
//Now add the result to the object you are passing to the View
Also keep in mind that you are not instantiating objects of type View_VisitorsForm but an anonymous object so assigning the result to empcount yet alone with the added FirstOrDefault will not compile
To pass this structure to the View and present it check this question
hope this helps you
var query = db.View_VisitorsForm.Where(o => o.VisitingDate >= new DateTime(2016,10,01) && o.VisitingDate <= new DateTime(2016, 10, 30)).GroupBy(G => G.Employee)
foreach (var item in query)
{
Console.WriteLine($"Employee Id {item.Key} : Count :{item.Count()}");
}

Group by day, time and id in one LINQ

I have a list of Example class elements:
public class Example
{
public long Id { get; set; }
public string Name { get; set; }
public DateTime SomeDate { get; set; }
}
Now I want to group it using ONE LINQ to make the following hierarchy:
public class GroupedByDay
{
public List<GroupedByTime> TimeGroup { get; set; }
}
public class GroupedByTime
{
public List<GroupedById> IdGroup { get; set; }
}
public class GroupedById
{
public string Name { get; set; }
}
So, the result is a list of type List<GroupedByDay> with the Examples grouped by days, hours (timespans?) within these days and finally by ids.
Can anyone help me with it?
[edit]
This is what I tried to group by Ids, but I think I should start from the other side maybe?
var result =
examples
.GroupBy(e => e.Id, e => new GroupedById
{
Name = e.Name
});
If you just want to group for displaying purposes, you don't need the classes GroupedByDay, GroupedByTime and GroupedById
Considering examples is an IEnumerable<Example>
var groupedExamples = from example in examples
group example by new {
example.SomeDate.Date, //Day
example.SomeDate.Hour, // Hour
example.Id // Id
} into g
select g;
Then you'll have an IEnumerable<IGrouping<,Example>> with the desired grouping:
foreach(var g in groupedExample){
Console.WriteLine(String.Format("Day {0} at hour {1} with id {2}", g.Key.Date, g.Key.Hour, g.Key.Id));
foreach(var example in g)
Console.WriteLine(" - " + example.Name);
}
I Usually write these code
public static DateTime GetDateByWeekDay(DateTime startDate, int week, Int32 day)
{
int Year = Getyear(startDate);
DateTime jan1 = new DateTime(Year, 1, 1);
int daysOffset = DayOfWeek.Monday - jan1.DayOfWeek;
DateTime firstMonday = jan1.AddDays(daysOffset);
var cal = CultureInfo.CurrentCulture.Calendar;
int firstWeek = cal.GetWeekOfYear(firstMonday, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
var weekNum = week;
if (firstWeek <= 1)
{
weekNum -= 1;}
var result = firstMonday.AddDays(weekNum * 7);
return result.AddDays(day);
}

Efficient way to call .Sum() on multiple properties

I have a function that uses LINQ to get data from the database and then I call that function in another function to sum all the individual properties using .Sum() on each individual property. I was wondering if there is an efficient way to sum all the properties at once rather than calling .Sum() on each individual property. I think the way I am doing as of right now, is very slow (although untested).
public OminitureStats GetAvgOmnitureData(int? fnsId, int dateRange)
{
IQueryable<OminitureStats> query = GetOmnitureDataAsQueryable(fnsId, dateRange);
int pageViews = query.Sum(q => q.PageViews);
int monthlyUniqueVisitors = query.Sum(q => q.MonthlyUniqueVisitors);
int visits = query.Sum(q => q.Visits);
double pagesPerVisit = (double)query.Sum(q => q.PagesPerVisit);
double bounceRate = (double)query.Sum(q => q.BounceRate);
return new OminitureStats(pageViews, monthlyUniqueVisitors, visits, bounceRate, pagesPerVisit);
}
private IQueryable<OminitureStats> GetOmnitureDataAsQueryable(int? fnsId, int dateRange)
{
var yesterday = DateTime.Today.AddDays(-1);
var nDays = yesterday.AddDays(-dateRange);
if (fnsId.HasValue)
{
IQueryable<OminitureStats> query = from o in lhDB.omniture_stats
where o.fns_id == fnsId
&& o.date <= yesterday
&& o.date > nDays
select new OminitureStats (
o.page_views.GetValueOrDefault(),
o.monthly_unique.GetValueOrDefault(),
o.visits.GetValueOrDefault(),
(double)o.bounce_rate.GetValueOrDefault()
);
return query;
}
return null;
}
public class OminitureStats
{
public OminitureStats(int PageViews, int MonthlyUniqueVisitors, int Visits, double BounceRate)
{
this.PageViews = PageViews;
this.MonthlyUniqueVisitors = MonthlyUniqueVisitors;
this.Visits = Visits;
this.BounceRate = BounceRate;
this.PagesPerVisit = Math.Round((double)(PageViews / Visits), 1);
}
public OminitureStats(int PageViews, int MonthlyUniqueVisitors, int Visits, double BounceRate, double PagesPerVisit)
{
this.PageViews = PageViews;
this.MonthlyUniqueVisitors = MonthlyUniqueVisitors;
this.Visits = Visits;
this.BounceRate = BounceRate;
this.PagesPerVisit = PagesPerVisit;
}
public int PageViews { get; set; }
public int MonthlyUniqueVisitors { get; set; }
public int Visits { get; set; }
public double PagesPerVisit { get; set; }
public double BounceRate { get; set; }
}
IIRC you can do all the sums in one go (as long as the query is translated to SQL) with
var sums = query.GroupBy(q => 1)
.Select(g => new
{
PageViews = g.Sum(q => q.PageViews),
Visits = g.Sum(q => q.Visits),
// etc etc
})
.Single();
This will give you one object which contains all the sums as separate properties.
I found out why it was throwing the NotSupportedException. I learned that Linq to Entity does not support constructors with parameters, So deleted the constructors and made changes in my query. I am a novice C# programmer, so let me know if my solution could be improved, but as of right now it is working fine.
public class OminitureStats
{
public int PageViews { get; set; }
public int MonthlyUniqueVisitors { get; set; }
public int Visits { get; set; }
public double PagesPerVisit { get; set; }
public double BounceRate { get; set; }
}
private IQueryable<OminitureStats> GetOmnitureDataAsQueryable(int? fnsId, int dateRange)
{
var yesterday = DateTime.Today.AddDays(-1);
var nDays = yesterday.AddDays(-dateRange);
if (fnsId.HasValue)
{
IQueryable<OminitureStats> query = from o in lhDB.omniture_stats
where o.fns_id == fnsId
&& o.date <= yesterday
&& o.date > nDays
select new OminitureStats() {
o.page_views.GetValueOrDefault(),
o.monthly_unique.GetValueOrDefault(),
o.visits.GetValueOrDefault(),
(double)o.bounce_rate.GetValueOrDefault()
};
return query;
}
return null;
}

Categories

Resources