Group By query in mvc5 - c#

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

Related

Combine two different types into one linq query and sort it

I have two database tables and I'm attempting to create a union query from them. They have different structures:
public partial class Notes
{
public int ID { get; set; }
public int VisitID { get; set; }
public string Note { get; set; }
public DateTime PostDate { get; set; }
public decimal AcctBalance {get; set; }
}
public partial class SystemNotes
{
public int ID {get; set;}
public int VisitID {get; set;}
public int FacilityID {get; set;}
public string Note {get; set;
public DateTime NoteDate {get ;set; }
}
What I want to do is end up with a list of all the data in Notes format sorted by PostDate. What I've tried so far is this:
List<Notes> requests = new List<Notes>();
requests = _context.Notes.Where(i => i.VisitID == VisitID && i.isActive == true).ToList();
List<SystemNotes> requests_s = new List<SystemNotes>();
requests_s = _context.SystemNotes.Where(i => i.VisitID == VisitID).ToList();
var unionA = from a in requests
select new
{
a.ID,
a.VisitID,
a.Note,
a.PostDate,
a.AcctBalance
};
var unionB = from b in requests_s
select new Notes()
{
ID = b.ID,
VisitID = (int)b.VisitID,
Note = b.Note,
PostDate = b.NoteDate,
AcctBalance = (decimal)0.00
};
List<Object> allS = (from x in unionA select (Object)x).ToList();
allS.AddRange((from x in unionB select (Object)x).ToList());
However, PostDate is no longer recognized as an element inside the Object so I can't sort on it. Also, it's in Object format not in Notes format which is what I want for where I'm sending my data. I'm stuck on this one point. Can you assist? Or am I doing this the wrong way in general?
If I correctly understand what you want:
List<Notes> myNotes = new List<Notes> {
new Notes () {
ID = 1,
VisitID = 2
}
};
List<SystemNotes> mySystemNotes = new List<SystemNotes> {
new SystemNotes () {
ID = 3,
VisitID = 4
}
};
var result = myNotes.Select (mn => new { mn.ID, mn.VisitID })
.Union(mySystemNotes.Select (msn => new { msn.ID, msn.VisitID }))
.OrderByDescending(a=>a.ID);
foreach (var currentItem in result)
{
Console.WriteLine ("ID={0}; VisitID={1}", currentItem.ID, currentItem.VisitID);
}

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

Issue Related to SelectMany function in LINQ

I have two tables in Database:
PostCalculationLine
PostCaluclationLineProduct
PostCalculationLineProduct(table2) contains Foriegn key of PostCalucationLineId(table1)
In C# code I have two different Models for these two tables as follows:
public class PostCalculationLine : BaseModel
{
public long Id{ get; set; }
public string Position { get; set; }
public virtual Order Order { get; set; }
public virtual Task Task { get; set; }
//some other properties go here
public virtual IList<PostCalculationLineProduct> PostCalculationLineProducts { get; set; }
}
and
public class PostCalculationLineProduct : BaseModel
{
public long Id {get;set;}
public string Description { get; set; }
//some other properties go here
}
Now in Entityframework code, I fetch data from PostCalculationLineProduct as follows:
PostCalculationLineRepository pclr = new PostCalculationLineRepository();
DataSourceResult dsrResult = pclr.Get()
.SelectMany(p => p.PostCalculationLineProducts)
.Where(c => c.Product.ProductType.Id == 1 && c.DeletedOn == null)
.Select(c => new HourGridViewModel()
{
Id = c.Id,
Date = c.From,
EmployeeName = c.Employee != null ?c.Employee.Name:string.Empty,
Description= c.Description,
ProductName = c.Product != null?c.Product.Name :string.Empty,
From = c.From,
To = c.Till,
Quantity = c.Amount,
LinkedTo = "OrderName",
Customer ="Customer"
PostCalculationLineId = ____________
})
.ToDataSourceResult(request);
In the above query I want to get PostCalculationLineId(from Table1) marked with underLine. How can I achieve this?
Thanks
You can use this overload of SelectMany to achieve this:-
DataSourceResult dsrResult = pclr.Get()
.SelectMany(p => p.PostCalculationLineProducts,
(PostCalculationLineProductObj,PostCalculationLineObj) =>
new { PostCalculationLineProductObj,PostCalculationLineObj })
.Where(c => c.PostCalculationLineProductObj.Product.ProductType.Id == 1
&& c.PostCalculationLineProductObj.DeletedOn == null)
.Select(c => new HourGridViewModel()
{
Id = c.PostCalculationLineProductObj.Id,
Date = c.PostCalculationLineProductObj.From,
//Other Columns here
PostCalculationLineId = c.PostCalculationLineObj.Id
};
This will flatten the PostCalculationLineProducts list and returns the flattened list combined with each PostCalculationLine element.

Orderby a string column in linq causes an error

I have a query like this :
List<PresentClass.userpresentation> q =
(dbconnect.tblUsers.Where(
i => i.permission == permission)
.Select(arg => new PresentClass.userpresentation {
email = arg.email, pass = arg.password,
name = arg.name+" "+arg.family })).ToList();
After adding an orderby :
List<PresentClass.userpresentation> q =
(dbconnect.tblUsers.Where(
i => i.permission == permission)
.Select(arg => new PresentClass.userpresentation {
email = arg.email, pass = arg.password,
name = arg.name+" "+arg.family })).OrderBy(i=>i.family).ToList();
I got this error :
The member
'Novitiate.AdminPortal.PresentationClass.PresentClass+userpresentation.family'
has no supported translation to SQL.
My class:
public class userpresentation
{
public string username { set; get; }
public string email { set; get; }
public string family { set; get; }
public string name { set; get; }
public string pass{ set; get; }
}
Why?
It looks like it's trying to translate the OrderBy() into a SQL statement on your projection.
Try adding the OrderBy() before Select() if you want the database to do the ordering, or after the ToList() if you want to do the ordering once the collection has been loaded.
var q = (dbconnect.tblUsers.Where(i => i.permission == permission)
.OrderBy(i=>i.family)
.Select(arg => new PresentClass.userpresentation {
email = arg.email,
pass = arg.password,
name = arg.name+" "+arg.family
})).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