Conversion of this SQL Query to LINQ - c#

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)
};

Related

at least one object must implement icomparable. orderby descending C#

I'm trying to order the list of Custom object by its nested object property updatedDate but it throws error. I want to order the Store list based on nested property field PartsInformation.updatedDate then by PartsDetail.updatedDate. If you need more details, let me know and I will try to update it. I tried with Icomparable but I'm new to that so I didn't proceed further.
Class Structure:
public class StoreHomeInfo
{
public string StoreID { get; set; }
public string StoreName { get; set; }
public List<OperationalUnit> OperationalUnitData { get; set; }
}
public class OperationalUnit
{
public string OunitID { get; set; }
public string OunitName { get; set; }
public List<PartsInformation> PartData { get; set; }
public List<PartsDetail> PartCost { get; set; }
}
public class PartsInformation
{
public string PartID { get; set; }
public string Partname { get; set; }
public string Summary { get; set; }
public string StoreID { get; set; }
public string OunitID { get; set; }
public DateTime? updatedDate { get; set; }
}
public class PartsDetail
{
public string PartsDetailID { get; set; }
public string PartDetailName { get; set; }
public string Summary { get; set; }
public string OunitID { get; set; }
public string StoreID { get; set; }
public DateTime? updatedDate { get; set; }
}
Sample Query :
var result = (from st in lstobjStoreDetails
group st by new { st.ID, st.Storename } into grouped
select new StoreHomeInfo()
{
StorID = grouped.Key.ID,
StoreName = grouped.Key.Storename,
OperationalUnitData = (from ser in lstobjOpUnitDetails
where ser.StorID.Equals(grouped.Key.ID)
group ser by new { ser.ID, ser.Ounitname } into
grouped1
select new OperationalUnit()
{
OunitID = grouped1.Key.ID,
OunitName = grouped1.Key.Ounitname,
PartsInformation = (from projes in lstobjpartDetails
where projes.OunitID.Equals(grouped1.Key.ID)
group serviceBS by new { projes.PartID, projes.Partname, projes.StorID, projes.OunitID,projes.updatedDate } into groupedparts
select new PartsInformation()
{
PartID = lstobjpartDetails.Where(q => q.StorID == grouped.Key.ID && q.OunitID == grouped1.Key.ID && q.PartID == groupedparts.Key.PartID).FirstOrDefault() != null ? lstobjpartDetails.Where(q => q.StorID == grouped.Key.ID && q.OunitID == grouped1.Key._ID && q.PartID == groupedparts.Key.PartID).FirstOrDefault().PartID : null,
Partname = groupedparts.Key.Partname,
Summary = groupedparts.Key.Summary,
OunitID = grouped1.Key.ID,
StorID = grouped.Key.ID,
updatedDate = Convert.ToDateTime(groupedparts.Key.updatedDate)
}).ToList(),
PartCost = (from pes in lstobjpartCostDetails
where pes.OunitID.Equals(grouped1.Key._ID)
group serviceBS by new { pes.PartsDetailID, pes.PartDetailName, pes.OunitID, pes.Summary pes.updatedDate, pes.StorID} into grouped2
select new PartsDetail()
{
PartsDetailID = lstobjpartCostDetails.Where(q => q.StorID == grouped.Key._ID && q.OunitID == grouped1.Key._ID && q.PartsDetailID == grouped2.Key.PartsDetailID).FirstOrDefault() != null ? lstobjpartCostDetails.Where(q => q.StorID == grouped.Key._ID && q.OunitID == grouped1.Key._ID && q.PartsDetailID == grouped2.Key.PartsDetailID).FirstOrDefault().PartsDetailID : null,
PartDetailName = grouped2.Key.PartDetailName,
Summary = grouped2.Key.Summary,
StorID = grouped.Key.ID,
OunitID = grouped1.Key.ID,
updatedDate = Convert.ToDateTime(grouped2.Key.updatedDate)
}).ToList()
}).ToList()
}).OrderByDescending(n => n.OperationalUnitData.OrderByDescending(p => p.PartCost != null && p.PartCost.Any() ? p.PartCost.OrderByDescending(q => q.updatedDate) : null)
.ThenBy(x => x.PartsInformation != null && x.PartsInformation.Any() ? x.PartsInformation.OrderByDescending(y => y.updatedDate) : null)).ToList();
This part of the code:
.OrderByDescending(p => p.PartCost != null && p.PartCost.Any() ? p.PartCost.OrderByDescending(q => q.updatedDate) : null)
is trying to order a list of OperationalUnits, but the key on which you're ordering by is a List<PartCost>. I suspect you want a member of that list to order by.
As an aside, you're trying to do a lot of work in one line and your code would be far clearer if you separated out methods to go into the OrderByDescending calls.

Can I customize a Select in Linq to select into an object?

I am using LINQ to select like this:
double views = Counts.btnCountViewsList
.Select(x => x.Views)
.DefaultIfEmpty(0).Average();
double btnCount = Counts.btnCountViewsList
.Select(x => x.BtnCount)
.DefaultIfEmpty(0).Average();
However I would like to know is this possible to do with one query and select into this object?
public class BtnCountViews
{
public BtnCountViews()
{
}
public int DayOfYear { get; set; }
public int Month { get; set; }
public int Year { get; set; }. // <<<<<<
public double BtnCount { get; set; } // <<<<<<
public double Views { get; set; }
}
It is as simple as this. This is just a guideline. I hope you could adapt it to your own needs.
Counts.btnCountViewsList.Select(x => new BtnCountViews()
{
BtnCount = 0,
DayOfYear = 0,
Month = 0,
Views = 0,
Year = 0
});

How to Add Collection List to a List in Asp.net MVC

I am Executing two linq queries for employees and contractors in a method and Converting to List then i am bind to list seperately declared in the model class.
I am executing this method every time for each company from list of companies by passing company id and model class as parameters like
public void GetEmployeeContractorsTimesheetNotEntered(int COMP_ID, string COMPANY_NAME, TimesheetModel model)
{
context = new ResLandEntities();
DateTime todayDate = DateTime.Now.Date;
DateTime thisWeekStartDate = todayDate.AddDays(-(int)todayDate.DayOfWeek).Date; //Start Date of Current Week
DateTime thisWeekEndDate = thisWeekStartDate.AddDays(6); // End Date of Current Week
var todaysDay = (int)DateTime.Now.DayOfWeek;
var employeesNotEnteredTimesheetList = (from emps in context.EMPLOYEE
join comp in context.COMPANY on emps.COMP_ID equals comp.ID
join notify in context.NOTIFICATION on emps.NOTIFICATION_ID equals notify.ID
from week in context.WEEK_CALENDER
from statlk in context.STATUS_LKUP
where !context.TIMESHEET.Any(m => m.WEEK_CAL_ID == week.ID
&& m.RES_TYPE == "EMPLOYEE"
&& m.RES_ID == emps.ID
&& m.COMP_ID == COMP_ID
&& m.IS_DELETED=="N") &&
week.WEEK_START_DT.Month == DateTime.Now.Month &&
week.WEEK_START_DT.Year == DateTime.Now.Year &&
week.WEEK_END_DT<=thisWeekEndDate &&
statlk.TYPE == "TIMESHEET" &&
statlk.STATE == "NOT_ENTERED" &&
emps.IS_DELETED == "N" &&
emps.COMP_ID==COMP_ID
select new TimesheetModel
{
EMP_ID = emps.ID,
EMP_COMP_ID = emps.COMP_EMP_ID,
EMPLOYEE_NAME = emps.FIRST_NAME + " " + emps.LAST_NAME,
COMPANY_NAME = comp.NAME,
PrimaryEmail = notify.PRI_EMAIL_ID,
SDate = week.WEEK_START_DT,
EDate = week.WEEK_END_DT,
EMP_STATUS = "NOT_ENTERED"
}).Distinct().ToList();
//Adding a Collection of List Here
model.GetTimesheetNotEnteredDetails.AddRange(employeesNotEnteredTimesheetList.GroupBy(m => m.EMP_ID).Select(m => m.First()).ToList());
var contractorsNotEnteredTimesheetList = (from contrs in context.CONTRACTOR
join client in context.CLIENT on contrs.CLIENT_ID equals client.ID
join notification in context.NOTIFICATION on contrs.NOTIFICATION_ID equals notification.ID
from week in context.WEEK_CALENDER
from statlk in context.STATUS_LKUP
where !context.TIMESHEET.Any(m => m.RES_ID == contrs.ID
&& m.WEEK_CAL_ID == week.ID
&& m.COMP_ID == COMP_ID
&& m.RES_TYPE == "CONTRACTOR"
&& m.IS_DELETED == "N")
&& week.WEEK_START_DT.Month == DateTime.Now.Month
&& week.WEEK_START_DT.Year == DateTime.Now.Year
&& statlk.STATE == "NOT_ENTERED"
&& statlk.TYPE == "TIMESHEET"
&& contrs.IS_DELETED == "N"
&& week.WEEK_START_DT <= thisWeekEndDate
&& contrs.COMP_ID == COMP_ID
select new TimesheetModel
{
EMP_ID=contrs.ID,
EMPLOYEE_NAME = contrs.FIRST_NAME + " " + contrs.LAST_NAME,
COMPANY_NAME = COMPANY_NAME,
SDate=week.WEEK_START_DT,
EDate=week.WEEK_END_DT,
CLIENT_NAME = client.NAME,
PrimaryEmail = notification.PRI_EMAIL_ID
}).Distinct().ToList();
//Adding Collection of List Here
model.GetContractorNotEnteredDetails .AddRange(contractorsNotEnteredTimesheetList.GroupBy(m => m.EMP_ID).Select(m => m.First()).ToList());
}
Now, my problem is I want to add list collection separately to two list, though i am binding the list separately , the two results of employees and contractors lists are clubbing in two lists like employees and contractors are in binding the two lists instead it should bind separately. whats going wrong, is it "AddRange" should not use for binding collection list to one list, is there any way for this solution, please help me anyone.
use this
var props = typeof(TimesheetModel).GetProperties();
DataTable dt= new DataTable();
dt.Columns.AddRange(
props.Select(p => new DataColumn(p.Name, p.PropertyType)).ToArray()
);
employeesNotEnteredTimesheetList.ForEach(
i => dt.Rows.Add(props.Select(p => p.GetValue(i, null)).ToArray())
);
var list1 = (from p in dt.AsEnumerable()
select p).ToList();
//similar for second list
Finally Got it.
Just I have separated Accessors in different Classes like
public class EmployeeTimesheetDetails
{
public int EMP_ID { get; set; }
public string EMP_COMP_ID { get; set; }
public string EMPLOYEE_NAME { get; set; }
public string COMPANY_NAME { get; set; }
public string PrimaryEmail { get; set; }
public DateTime SDate { get; set; }
public DateTime EDate { get; set; }
public string EMP_STATUS { get; set; }
}
public class ContractorsTimesheetDetails
{
public int CONTR_ID { get; set; }
public string CONTRACTOR_NAME { get; set; }
public string COMPANY_NAME { get; set; }
public DateTime SDate { get; set; }
public DateTime EDate { get; set; }
public string CLIENT_NAME { get; set; }
public string PrimaryEmail { get; set; }
}
and modified the two list in model class like
public List<EmployeeTimesheetDetails> GetTimesheetNotEnteredDetails { get; set;}
public List<ContractorsTimesheetDetails> GetContractorNotEnteredDetails { get; set; }
This modification is cleared my issue .
You need to have two properties in the class TimesheetModel, something like this:
public class CompanyListModel
{
public List<CompanyModel> CompanyList { get; set; };
}
public class CompanyModel
{
public List<TimesheetModel > EmployeesNotEnteredTimesheetList { get; set; };
public List<TimesheetModel > ContractorsNotEnteredTimesheetList { get; set; };
}
Then add like this:
public void GetEmployeeContractorsTimesheetNotEntered(int COMP_ID, string COMPANY_NAME, CompanyListModel model)
{
// your stuff
CompanyModel conpanyModel = new CompanyModel();
conpanyModel.EmployeesNotEnteredTimesheetList = employeesNotEnteredTimesheetList.GroupBy(m => m.EMP_ID).Select(m => m.First()).ToList();
conpanyModel.ContractorsNotEnteredTimesheetList = contractorsNotEnteredTimesheetList.GroupBy(m => m.EMP_ID).Select(m => m.First()).ToList();
model.CompanyList.add(companyModel);
// your stuff
}

How are treated nonpersistent data in DevExpress XAF?

I need to create some queries and these queries will be used to create graphs in a dashboard. The queries are a lot of calculations and are nonpersistent classes.
First I created the class and only about this I have HPerformance_ListView and HPerformance_DetailView but I don't have a data provider to populate it. The system tries to populate it from EF context, that is not possible.
[NavigationItem]
[NonPersistent]
public class HPerformance
{
public decimal Valor { get; set; }
public decimal Meta { get; set; }
public decimal Percentual { get; set; }
}
And the query class
public class MetasVendas
{
public MetasVendas()
{
fromDate = DateTime.Now.AddMonths(-1);
toDate = DateTime.Now;
revenda = 0;
}
public DateTime fromDate { get; set; }
public DateTime toDate { get; set; }
public long revenda { get; set; }
public BindingList<HPerformance> _hPerformance()
{
var r = _calculoMetaEValor();
var rr = r.GroupBy(g => true).Select(s => new HPerformance()
{
Valor = s.Sum(v => v.TotalUSacess + v.TotalUSradio),
Meta = s.Sum(v => v.Meta),
Percentual = s.Sum(vv => vv.TotalUSacess + vv.TotalUSradio) / s.Sum(vv => vv.Meta)
});
return new BindingList<HPerformance>(rr.ToList());
}
In the dashboard controller this is the code that I don't know how to handle. My example doesn't work
public partial class DashboardDealerGoalExecute : ViewController<DashboardView>
{
void parametersViewItem_ControlCreated(object sender, EventArgs e)
{
DashboardViewItem viewItem = (DashboardViewItem)sender;
if (viewItem.Id == "HPerformance")
{
ListView _hPerformance = (ListView)viewItem.InnerView;
if (parameters != null && parameters.Dealer != null)
{
BindingList<HPerformance> hp =
new MetasVendas()
{
fromDate = parameters.FromDate,
toDate = parameters.ToDate,
revenda = parameters.Dealer.ID
}._hPerformance();
_hPerformance.CurrentObject = hp;
}
}
HPerformance is a dashboard item and is connected to HPerformance class (1st code). How do I setup HPerformance_ListView to be populated by _hPerformance() method?
Thanks,
Marco Castro

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