How to avg() in linq - c#

I'm trying write my sql commang to Linq:
SQL:
select avg(sub.evaluation) from submit_task sub where student_id='" + idStudent + "' and state='close';
Linq:
double avg = (ado.submit_task.Where(r => (r.id == idStudent && r.state == "close")).Average(r => r.evaluation));
avgStudent = avg.ToString();
but this is not working, when I delete && r.state == "close" statement, I got result, but it's incorrect.
thank you.

I have tried the same with a sample set of data and it works fine
List<student> students = new List<student>
{
new student{id="1",state="close",evaluation=5},
new student{id="1",state="close",evaluation=4}
};
double avg = (students.Where(r => (r.id == "1" && r.state == "close")).Average(r => r.evaluation));
public class student
{
public string id { get; set; }
public string state { get; set; }
public int evaluation { get; set; }
}
may be you should check the data in the db or modify the state="close" part of the query

ok, here's code, which working:
var avgEvalClose = (from sub in ado.submit_task
where sub.student_id.Equals(idStudent)
where sub.state.Equals("close")
select sub.evaluation).Average();
avgStudent = avgEvalClose.ToString();

Related

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

EF get list of parent entities that have list of child

I have to next 2 entities in my project
public class Product
{
public Product()
{
this.ProductImages = new HashSet<ProductImage>();
this.ProductParams = new HashSet<ProductParam>();
}
public int ID { get; set; }
public int BrandID { get; set; }
public int CodeProductTypeID { get; set; }
public string SeriaNumber { get; set; }
public string ModelNumber { get; set; }
public decimal Price { get; set; }
public bool AvailableInStock { get; set; }
public virtual Brand Brand { get; set; }
public virtual CodeProductType CodeProductType { get; set; }
public virtual ICollection<ProductImage> ProductImages { get; set; }
public virtual ICollection<ProductParam> ProductParams { get; set; }
}
public class ProductParam
{
public int Id { get; set; }
public int ProductId { get; set; }
public int CodeProductParamId { get; set; }
public string Value { get; set; }
public virtual Product Product { get; set; }
public virtual CodeProductParam CodeProductParam { get; set; }
}
and I want to get list of Products which has list of specified parameters
var prodParamCritria = new List<ProductParam>()
{
new ProductParam(){CodeProductParamId =1, Value="Black" },
new ProductParam(){CodeProductParamId =2, Value="Steal"}
};
in sql I can do it by using EXISTS clause twise
SELECT *
FROM Products p
WHERE EXISTS (
SELECT *
FROM ProductParams pp
WHERE pp.ProductId = p.ID
AND (pp.CodeProductParamId = 1 AND pp.[Value] = N'Black')
)
AND EXISTS (
SELECT *
FROM ProductParams pp
WHERE pp.ProductId = p.ID
AND pp.CodeProductParamId = 2
AND pp.[Value] = N'Steal'
)
How can i get same result by EF methods or linq
Try this:
var products= db.Products.Where(p=>p.ProductParams.Any(pp=>pp.CodeProductParamId == 1 && pp.Value == "Black") &&
p.ProductParams.Any(pp=>pp.CodeProductParamId == 2 && pp.Value == "Steal"));
Update
The problem in work with that list of ProductParam to use it as a filter is that EF doesn't know how to translate a PodructParam object to SQL, that's way if you execute a query like this:
var products2 = db.Products.Where(p => prodParamCritria.All(pp => p.ProductParams.Any(e => pp.CodeProductParamId == e.CodeProductParamId && pp.Value == e.Value)));
You will get an NotSupportedException as you comment in the answer of #BostjanKodre.
I have a solution for you but probably you will not like it. To resolve that issue you could call the ToList method before call the Where. This way you will bring all products to memory and you would work with Linq to Object instead Linq to Entities, but this is extremely inefficient because you are filtering in memory and not in DB.
var products3 = db.Products.ToList().Where(p => prodParamCritria.All(pp => p.ProductParams.Any(e => pp.CodeProductParamId == e.CodeProductParamId && pp.Value == e.Value)));
If you want filter by one criteria then this could be more simple and you are going to be able filtering using a list of a particular primitive type. If you, for example, want to filter the products only by CodeProductParamId, then you could do this:
var ids = new List<int> {1, 2};
var products = db.Products.Where(p => ids.All(i=>p.ProductParams.Any(pp=>pp.CodeProductParamId==i))).ToList();
This is because you are working with a primitive type and not with a custom object.
I suppose something like that should work
db.Product.Where(x => x.ProductParams.FirstOrDefault(y => y.CodeProductParamId == 1) != null && x.ProductParams.FirstOrDefault(y => y.CodeProductParamId == 2) != null).ToList();
or better
db.Product.Where(x => x.ProductParams.Any(y => y.CodeProductParamId == 1) && x.ProductParams.Any(y => y.CodeProductParamId == 2)).ToList();
Ok, if you need to make query on parameters in list prodParamCriteria it will look like this:
db.Product.Where(x => prodParamCritria.All(c=> x.ProductParams.Any(p=>p.CodeProductParamId == c.CodeProductParamId && p.Value== c.Value))).ToList();
I forgot that complex types cannot be used in query database, so i propose you to convert your prodParamCriteria to dictionary and use it in query
Dictionary<int, string> dctParams = prodParamCritria.ToDictionary(x => x.CodeProductParamId , y=>y.Value);
db.Product.Where(x => dctParams.All(c => x.ProductParams.Any(p=> p.CodeProductParamId == c.Key && p.Value== c.Value))).ToList();
another variation:
IEnumerable<Int32> lis = prodParamCritria.Select(x => x.CodeProductParamId).ToList();
var q = Products.Select(
x => new {
p = x,
cs = x.ProductParams.Where(y => lis.Contains(y.Id))
}
).Where(y => y.cs.Count() == lis.Count()).
ToList();
with a named class like (or maybe without, but not in linqpad)
public class daoClass {
public Product p {get; set;}
public Int32 cs {get; set;}
}
IEnumerable<Int32> lis = prodParamCritria.Select(x => x.CodeProductParamId).ToList();
var q = Products.Select(
x => new daoClass {
p = x,
cs = x.ProductParams.Where(y => lis.Contains(y.Id))
}
).Where(y => y.cs.Count() == lis.Count()).
SelectMany(y => y.p).
ToList();

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
}

Grouping and flattening list with linq and lambda

I have the following class
public class SolicitacaoConhecimentoTransporte
{
public long ID { get; set; }
public string CodigoOriginal { get; set; }
public DateTime Data { get; set; }
public List<CaixaConhecimentoTransporte> Caixas { get; set; }
}
I would like to know if there is a way of achiveing the same behavior of the code below using Linq (with lambda expression syntax),
List<SolicitacaoConhecimentoTransporte> auxList = new List<SolicitacaoConhecimentoTransporte>();
foreach (SolicitacaoConhecimentoTransporte s in listaSolicitacao)
{
SolicitacaoConhecimentoTransporte existing =
auxList.FirstOrDefault(f => f.CodigoOriginal == s.CodigoOriginal &&
f.Data == s.Data &&
f.ID == s.ID);
if (existing == null)
{
auxList.Add(s);
}
else
{
existing.Caixas.AddRange(s.Caixas);
}
}
return auxList;
In other words, group all entities that have equal properties and flat all lists into one.
Thanks in advance.
Use anonymous object to group by three properties. Then project each group to new SolicitacaoConhecimentoTransporte instance. Use Enumerable.SelectMany to get flattened sequence of CaixaConhecimentoTransporte from each group:
listaSolicitacao.GroupBy(s => new { s.CodigoOriginal, s.Data, s.ID })
.Select(g => new SolicitacaoConhecimentoTransporte {
ID = g.Key.ID,
Data = g.Key.Data,
CodigoOriginal = g.Key.CodigoOriginal,
Caixas = g.SelectMany(s => s.Caixas).ToList()
}).ToList()

can't select into class using linq

I have a query that works fine when using an anonymous type but as soon as I try to un-anonymize it it fails to select all values into the class.
here is the linq i'm using (in combination with Subsonic 3):
var producten = (from p in Premy.All()
join pr in Producten.All() on p.dekking equals pr.ID
where p.kilometragemax >= 10000 &&
p.CCmin < 3000 &&
p.CCmax >= 3000 &&
p.leeftijdmax >= DateTime.Today.Subtract(car.datumEersteToelating).TotalDays / 365
group p by new { pr.ID, pr.Naam, pr.ShortDesc, pr.LongDesc } into d
select new
{
ID = d.Key.ID,
Dekking = d.Key.Naam,
ShortDesc = d.Key.ShortDesc,
LongDesc = d.Key.LongDesc,
PrijsAlgemeen = d.Min(x => x.premie),
PrijsAlgemeenMaand = d.Min(x => x.premie),
PrijsMerkdealerMaand = d.Min(x => x.premie),
PrijsMerkdealer = d.Min(x => x.premie)
}).ToList();
When I change it to:
List<QuotePremies> producten = (from p in Premy.All()
join pr in Producten.All() on p.dekking equals pr.ID
where p.kilometragemax >= 10000 &&
p.CCmin < 3000 &&
p.CCmax >= 3000 &&
p.leeftijdmax >= DateTime.Today.Subtract(car.datumEersteToelating).TotalDays / 365
group p by new { pr.ID, pr.Naam, pr.ShortDesc, pr.LongDesc } into d
select new QuotePremies
{
ID = d.Key.ID,
Dekking = d.Key.Naam,
ShortDesc = d.Key.ShortDesc,
LongDesc = d.Key.LongDesc,
PrijsAlgemeen = d.Min(x => x.premie),
PrijsAlgemeenMaand = d.Min(x => x.premie),
PrijsMerkdealerMaand = d.Min(x => x.premie),
PrijsMerkdealer = d.Min(x => x.premie)
}).ToList();
in combination with this class:
public class QuotePremies
{
public byte ID { get; set; }
public string Dekking { get; set; }
public string ShortDesc { get; set; }
public string LongDesc { get; set; }
public decimal PrijsAlgemeen { get; set; }
public decimal PrijsAlgemeenMaand { get; set; }
public decimal PrijsMerkdealer { get; set; }
public decimal PrijsMerkdealerMaand { get; set; }
}
it doesn't give me an error but all values in the class are 0 except for QuotePremies.ID, QuotePremies.ShortDesc and QuotePremies.LongDesc. No clue why that happens.
See if using conversion helps
PrijsAlgemeen = Convert.ToDecimal(d.Min(x => x.premie))
I believe the problem has to do with casting. Why not write and extension method for IEnumberable which would take this query result and return a collection of List. It could look something like this:
public static class Extensions
{
// extends IEnumerable to allow conversion to a custom type
public static TCollection ToMyCustomCollection<TCollection, T>(this IEnumerable<T> ienum)
where TCollection : IList<T>, new()
{
// create our new custom type to populate and return
TCollection collection = new TCollection();
// iterate over the enumeration
foreach (var item in ienum)
{
// add to our collection
collection.Add((T)item);
}
return collection;
}
}
Thanks to kek444 for helping me with a similar problem

Categories

Resources