I am having issues with my nested foreach loop. I'm trying to populate data from by database to my list with information about car information (company, different car models). My issue has to do with my inner loop, and not being able to continue populating my list.
The results that I'm expecting is this:
"CompanyId": 1,
"CompanyName": "Toyota"
"ParentVehicleId": 2,
"ParentVehicleName": "Camry",
"ChildVehicleId": 4,
"ChildVehicleName":"Camry/Scepter"
"CompanyId": 1,
"CompanyName": "Toyota"
"ParentVehicleId": 4,
"ParentVehicleName": "Crown"
"ChildVehicleId": 0,
"ChildVehicleName":"N/A"
"CompanyId": 12,
"CompanyName": "Hyundai"
"ParentVehicleId": 13,
"ParentVehicleName": "Accent",
"ChildVehicleId": 0,
"ChildVehicleName":"N/A"
etc...
But what I'm actually getting is only these two:
"CompanyId": 1,
"CompanyName": "Toyota"
"ParentVehicleId": 2,
"ParentVehicleName": "Camry",
"ChildVehicleId": 3,
"ChildVehicleName":"Camry/Vista"
"CompanyId": 1,
"CompanyName": "Toyota"
"ParentVehicleId": 2,
"ParentVehicleName": "Camry",
"ChildVehicleId": 4,
"ChildVehicleName":"Camry/Scepter"
This is a snippet of my db table:
Vehicle Table
|----------------------------------------------|
| VehicleId | ManufactId | BrandName |
|----------------------------------------------|
| 1 | 1 | Toyota |
|----------------------------------------------|
| 2 | 1 | Camry |
|----------------------------------------------|
| 3 | 2 | Camry/Vista |
|----------------------------------------------|
| 4 | 2 | Camry/Scepter |
|----------------------------------------------|
| 5 | 4 | Crown |
|----------------------------------------------|
| 6 | 5 | Supra |
|----------------------------------------------|
C# code
public List<VehicleListModel>> VehicleMethod()
{
List<VehicleListModel> vehicleList = new List<VehicleListModel>();
foreach (var item in companyInfo)
{
var parentInfo = _context.VehicleTable.Where(y => item.VehicleId == y.ManufactId).ToList();
foreach (var item2 in parentInfo)
{
var childInfo = _context.VehicleTable.Where(y => item2.VehicleId == y.ManufactId).ToList();
foreach (var item3 in childInfo)
{
VehicleListModel vehList = new VehicleListModel();
//if ChildVehicleId does not exist, 0 & N/A are
//returned
vehList.CompanyId = item.VehicleId;
vehList.CompanyName = item?.BrandName ?? "N/A";
vehicleList.Add(vehList);
}
}
}
return vehicleList;
}
The problem is basically how your data is connected.
Let's take Toyota:
|----------------------------------------------|----------------|
| VehicleId | ManufactId | BrandId | BrandName |
|----------------------------------------------|----------------|
| 1 | null | 1 | Toyota |
|----------------------------------------------|----------------|
| 2 | 1 | 1 | Camry |
|----------------------------------------------|----------------|
| 3 | 2 | 1 | Camry/Vista |
|----------------------------------------------|----------------|
| 4 | 2 | 1 | Camry/Scepter |
As you can see, the model Camry is the relationship between the versions and the company.
When VehicleId is 2 (from Camry) you look for records where ManufactId is 2 (Vista and Scepter).
For Nissan instead:
|----------------------------------------------|----------------|
| VehicleId | ManufactId | BrandId | BrandName |
|----------------------------------------------|----------------|
| 9 | null | 9 | Nissan |
|----------------------------------------------|----------------|
| 10 | 9 | 9 | Datsun |
|----------------------------------------------|----------------|
| 11 | 9 | 9 | Datsun 13T |
Datsun doesn't have childs (no record have ManufactId equal to 10). Update Datsun 13 T record to ManufactId 10 to see it.
The same goes for the rest.
Moreover, because you hydrate the objects of the list inside the innermost foreach loop (and you never reach that code) you don't even get the empty objects.
If the data is wrong and you can't do anything about it, one possible way to handle these cases is to generate objects with the available info:
....
List<VehicleListModel> vehicleList = new List<VehicleListModel>();
var companies = _context.Where(x => x.ManufactId == null).ToList();
foreach (var company in companies)
{
var models = _context.Where(y => company.VehicleId == y.ManufactId).ToList();
if (models.Any())
{
foreach (var model in models)
{
var versions = _context.Where(y => model.VehicleId == y.ManufactId).ToList();
if (versions.Any())
{
foreach (var version in versions)
{
VehicleListModel vehList = new VehicleListModel();
vehList.CompanyId = company.VehicleId;
vehList.CompanyName = company?.BrandName ?? "N/A";
vehList.ParentVehicleId = model?.VehicleId ?? 0;
vehList.ParentVehicleName = model?.BrandName ?? "N/A";
vehList.ChildVehicleId = version?.VehicleId ?? 0;
vehList.ChildVehicleName = version?.BrandName ?? "N/A";
vehicleList.Add(vehList);
}
}
else
{
VehicleListModel vehList = new VehicleListModel();
vehList.CompanyId = company.VehicleId;
vehList.CompanyName = company.BrandName;
vehList.ParentVehicleId = model.VehicleId;
vehList.ParentVehicleName = model.BrandName;
vehList.ChildVehicleId = 0;
vehList.ChildVehicleName = "N/A";
vehicleList.Add(vehList);
}
}
}
else
{
VehicleListModel vehList = new VehicleListModel();
vehList.CompanyId = company.VehicleId;
vehList.CompanyName = company.BrandName;
vehList.ParentVehicleId = 0;
vehList.ParentVehicleName = "N/A";
vehList.ChildVehicleId = 0;
vehList.ChildVehicleName = "N/A";
vehicleList.Add(vehList);
}
}
....
Also, as #Yair suggested, you need to change Crown to ManufactId = 1
You are overriding the vehList instance in each iteration. Instead, you should move its initialization to the inner most loop, so a new instance is added to the list in each iteration:
foreach (var item in companyInfo)
{
var parentInfo = _context.VehicleTable.Where(y => item.VehicleId == y.ManufactId).ToList();
foreach (var item2 in parentInfo)
{
// This should be removed from the code:
// VehicleListModel vehList = new VehicleListModel();
var childInfo = _context.VehicleTable.Where(y => item2.VehicleId == y.ManufactId).ToList();
foreach (var item3 in childInfo)
{
// Instead, it's initialized here:
VehicleListModel vehList = new VehicleListModel();
//if ChildVehicleId does not exist, 0 & N/A are
//returned
vehList.CompanyId = item.VehicleId;
vehList.CompanyName = item?.BrandName ?? "N/A";
vehList.ParentVehicleId = item2?.VehicleId ?? 0;
vehList.ParentVehicleName = item2?.BrandName ?? "N/A";
vehList.ChildVehicleId = item3?.VehicleId ?? 0;
vehList.ChildVehicleName = item3?.BrandName ?? "N/A";
vehicleList.Add(vehList);
}
}
}
Related
How to multiply and sum all numeric children properties in LINQ
I have an object as follows
public class ResourceTier
{
//primary key. no duplicate
public int Id { get; set; }
public int ParentId { get; set; }
public decimal Volume { get; set; } //has value
public decimal UnitRate { get; set; } //has value
public decimal TotalPrice { get; set; } //has no value
}
The TotalPrice default value is 0. This is the property where I want to fill the value. The TotalPrice should be filled by multiplying the UnitRate and Volume properties and then summing of all the children if any.
This is the data
| Id | ParentId | Volume | UnitRate | TotalPrice |
| 1 | 0 | - | - | 180 |
| 2 | 0 | - | - | 30 |
| 3 | 1 | - | - | 130 |
| 4 | 1 | 5 | 10 | 50 |
| 5 | 2 | 3 | 10 | 30 |
| 6 | 3 | - | - | 50 |
| 7 | 3 | 2 | 40 | 80 |
| 8 | 6 | 4 | 10 | 40 |
| 9 | 6 | 1 | 10 | 10 |
When I try this, it is not working. This code has only the sum of the direct children but not all children (grand grand children and so on)
List<ResourceTier> result = ...;
result.ForEach(x => x.TotalPrice =
result.Where(c => c.ParentId == x.Id).Count() == 0 ?
s.UnitRates * s.Volume :
result.Where(c => c.ParentId == x.Id).Select(s => (s.UnitRates * s.Volume)).Sum());
A solution using only Linq will be hard to achieve, because it will typically only respect one level of children. In order to get the total of the grandchildren too, you have to walk the tree completely in order to get the sum of the children (and their children).
You have to create a method that uses recursion which means that it will call itself again with a different set of parameters. This way, you can get the total of the children first and then assign the value of the current node, e.g.:
private decimal SetTotal(IEnumerable<ResourceTier> tiers, ResourceTier current)
{
current.Total = current.Volume * current.UnitRate;
// Get children of current node
var children = tiers.Where(x => x.ParentId == current.Id && x.Id != current.Id); // The second condition explicitely excludes the current node to avoid infinite loops
foreach(var child in children)
current.Total += SetTotal(tiers, child); // Call method again for children
return current.Total;
}
The first call to the function would use the ids of all items that do not have a parent, e.g.:
foreach(var topLevelNode in tiers.Where(x => x.ParentId == 0))
SetTotal(tiers, topLevelNode);
Please note that the code above should demonstrate the principle of recursion. For sure there are more efficient ways to solve this a bit faster.
As other answers you need to calculate totalprice recursively:
public static decimal total(ResourceTier rt, List<ResourceTier> data)
{
if (data.Where(x=>x.ParentId==rt.Id).Count()==0)
return rt.Volume*rt.UnitRate;
else
{
var sum= data.Where(x => x.ParentId == rt.Id).Select(x=>total( x,data)).Sum();
return rt.UnitRate*rt.Volume+sum;
}
}
And the use this method:
var data = new List<ResourceTier> {
new ResourceTier{ Id=1, ParentId=0, Volume=0, UnitRate=0, TotalPrice=0 },
new ResourceTier{ Id=2, ParentId=0, Volume=0, UnitRate=0, TotalPrice=0 },
new ResourceTier{ Id=3, ParentId=1, Volume=0, UnitRate=0, TotalPrice=0 },
new ResourceTier{ Id=4, ParentId=1, Volume=5, UnitRate=10, TotalPrice=0 },
new ResourceTier{ Id=5, ParentId=2, Volume=3, UnitRate=10, TotalPrice=0 },
new ResourceTier{ Id=6, ParentId=3, Volume=0, UnitRate=0, TotalPrice=0 },
new ResourceTier{ Id=7, ParentId=3, Volume=2, UnitRate=40, TotalPrice=0 },
new ResourceTier{ Id=8, ParentId=6, Volume=4, UnitRate=10, TotalPrice=0 },
new ResourceTier{ Id=9, ParentId=6, Volume=1, UnitRate=10, TotalPrice=0 },
};
var result = data.Select(x=>new ResourceTier { Id=x.Id, ParentId=x.ParentId, UnitRate=x.UnitRate, Volume=x.Volume, TotalPrice= total(x, data) }).ToList();
output :
LINQ can't change your source collection!
However you can create a new collection of ResourceTiers that match your requirements. After that you can decide to assign that to your output, or decide to save them in your database, table, etc.
IEnumerable<ResourceTier> sourceCollection = ...
IEnumerable<ResourceTier> resourceTiersWithTotalPrice = sourceCollection
.Select(resourceTier => new ResourceTier
{
Id = resourceTier.Id,
ParentId = resourceTier.ParentId,
...
TotalPrice = resourceTier.Volume * resourceTier.UnitRate,
});
This is my code:
public class Photos
{
public long PhotoLabel { get; set; }
public int UserID { get; set; }
}
List<Photos> photolist = new List<Photos>();
var result1 = photolist.OrderByDescending(p => p.PhotoLabel).ThenBy(r => r.UserID).ToList();
If I display the contents now, this is what I get (First sorted in descending order of PhotoLabel and then sorted by UserID:
|------|---------------------|---------------------|
| Row | UserID | PhotoLabel |
|----------------------------|---------------------|
| 1 | 92 | 20180729181046 |
|----------------------------|---------------------|
| 2 | 92 | 20180729181041 |
|----------------------------|---------------------|
| 3 | 92 | 20180729181037 |
|----------------------------|---------------------|
| 4 | 88 | 20180729174415 |
|----------------------------|---------------------|
| 5 | 88 | 20180729174405 |
|----------------------------|---------------------|
| 6 | 04 | 20180729174358 |
|----------------------------|---------------------|
| 7 | 1 | 20170924183847 |
|----------------------------|---------------------|
| 8 | 1 | 20170921231422 |
|----------------------------|---------------------|
| 9 | 1 | 20170920194624 |
|----------------------------|---------------------|
| 10 | 32 | 20170820114728 |
|----------------------------|---------------------|
| 11 | 32 | 20170820114725 |
|----------------------------|---------------------|
| 12 | 32 | 20170820114421 |
|----------------------------|---------------------|
| 13 | 32 | 20170820114416 |
|----------------------------|---------------------|
| 14 | 1 | 20170225151023 |
|----------------------------|---------------------|
| 15 | 1 | 20170225151000 |
|----------------------------|---------------------|
| 16 | 1 | 20170225150957 |
|----------------------------|---------------------|
From the sorted table above, this is what I want to achieve:
Display groups of UserIDs and PhotoLabels where UserIDs appear 3 or more times in one group (eg: rows 4 and 5 where UserID=88 and row 6 where UserID=04 should be eliminated since the UserID=88 appears just twice in the group and UserID=04 appears only once in the group).
Display only the top most group of UserIDs and exclude any repeating UserIDs (eg: rows 7,8 and 9 displays the UserID=1 group. Don't display any other UserID=1 group such as rows 14,15 and 16. )
The expected result from query should be:
|------|---------------------|---------------------|
| Row | UserID | PhotoLabel |
|----------------------------|---------------------|
| 1 | 92 | 20180729181046 |
|----------------------------|---------------------|
| 2 | 92 | 20180729181041 |
|----------------------------|---------------------|
| 3 | 92 | 20180729181037 |
|----------------------------|---------------------|
| 7 | 1 | 20170924183847 |
|----------------------------|---------------------|
| 8 | 1 | 20170921231422 |
|----------------------------|---------------------|
| 9 | 1 | 20170920194624 |
|----------------------------|---------------------|
| 10 | 32 | 20170820114728 |
|----------------------------|---------------------|
| 11 | 32 | 20170820114725 |
|----------------------------|---------------------|
| 12 | 32 | 20170820114421 |
|----------------------------|---------------------|
| 13 | 32 | 20170820114416 |
|----------------------------|---------------------|
Thank you so much in in advance! :-)
If I am not misunderstood the requirement, below function properly works (but it shouldn't the most efficient solution)
protected List<AnObject> aFunction(List<AnObject> sortedList)
{
//Display groups of UserIDs and PhotoLabels where UserIDs appear 3 or more times in one group (eg: rows 4 and 5 where UserID = 88 and row 6 where UserID = 04 should be eliminated since the UserID = 88 appears just twice in the group and UserID = 04 appears only once in the group).
//Display only the top most group of UserIDs and exclude any repeating UserIDs(eg: rows 7, 8 and 9 displays the UserID = 1 group.Don't display any other UserID=1 group such as rows 14,15 and 16.
int pivot = -1;
int cnt = 0;
List<AnObject> masterList = new List<AnObject>();
List<AnObject> subList = new List<AnObject>();
//List<int> Excluded = new List<int>();
foreach (AnObject r in sortedList)
{
if (pivot != r.UserID)
{
if (cnt > 2)
{
masterList.AddRange(subList);
//Excluded.Add(pivot);
}
subList.Clear();
pivot = -1;
cnt = 0;
//if (!Excluded.Contains(r.UserID))
if (!masterList.Any(x => x.UserID == r.UserID))
{
pivot = r.UserID;
}
}
subList.Add(r);
cnt++;
}
return masterList;
}
To call it for testing
protected class AnObject
{
public AnObject(int uid, string photolabel)
{
this.UserID = uid;
this.PhotoLabel = photolabel;
}
public int UserID { get; set; }
public string PhotoLabel { get; set; }
}
protected void Execute()
{
List<AnObject> sortedList = new List<AnObject>();
sortedList.Add(new AnObject(92, "anystring"));
sortedList.Add(new AnObject(92, "anystring"));
sortedList.Add(new AnObject(92, "anystring"));
sortedList.Add(new AnObject(88, "anystring"));
sortedList.Add(new AnObject(88, "anystring"));
sortedList.Add(new AnObject(4, "anystring"));
sortedList.Add(new AnObject(1, "anystringfirst"));
sortedList.Add(new AnObject(1, "anystringfirst"));
sortedList.Add(new AnObject(1, "anystringfirst"));
sortedList.Add(new AnObject(32, "anystring"));
sortedList.Add(new AnObject(32, "anystring"));
sortedList.Add(new AnObject(32, "anystring"));
sortedList.Add(new AnObject(32, "anystring"));
sortedList.Add(new AnObject(1, "anystringafter"));
sortedList.Add(new AnObject(1, "anystringafter"));
sortedList.Add(new AnObject(1, "anystringafter"));
List<AnObject> bb = aFunction(sortedList);
}
Please wait! This is not the final answer! a little bit further modification is needed! modification is underway.
List<Photos> photolist = new List<Photos>()
{
new Photos() {UserID = 92, PhotoLabel = 20180729181046},
new Photos() {UserID = 92, PhotoLabel = 20180729181041},
new Photos() {UserID = 92, PhotoLabel = 20180729181037},
new Photos() {UserID = 88, PhotoLabel = 20180729174415},
new Photos() {UserID = 88, PhotoLabel = 20180729174405},
new Photos() {UserID = 04, PhotoLabel = 20180729174358},
new Photos() {UserID = 1, PhotoLabel = 20170924183847},
new Photos() {UserID = 1, PhotoLabel = 20170921231422},
new Photos() {UserID = 1, PhotoLabel = 20170920194624},
new Photos() {UserID = 32, PhotoLabel = 20170820114728},
new Photos() {UserID = 32, PhotoLabel = 20170820114725},
new Photos() {UserID = 32, PhotoLabel = 20170820114421},
new Photos() {UserID = 32, PhotoLabel = 20170820114416},
new Photos() {UserID = 1, PhotoLabel = 20170225151023},
new Photos() {UserID = 1, PhotoLabel = 20170225151000},
};
var photolist2 = photolist.GroupBy(g => g.UserID)
.Select(p => new
{
UserId = p.Key,
Count = p.Count()
})
.ToList();
var filteredPhotoList = photolist
.Join(photolist2,
photo => photo.UserID,
photo2 => photo2.UserId,
(photo, photo2) => new {UserId = photo.UserID, PhotoLabel =
photo.PhotoLabel, Count = photo2.Count})
.Where(p => p.Count > 2).Select(p => new
{
p.UserId, p.PhotoLabel
}).OrderByDescending(p => p.PhotoLabel).ThenBy(p => p.UserId).ToList();
Thank you all for your help. SKLTFZ's and TanvirArjel's answers were close but didn't achieve the expected results. I realized that you cannot achieve everything described above in Linq, so this is what I came up with and it achieves everything listed above:
PS: I renamed var result1 to ordered_photolist
List<Photos> ordered_photolist = photolist.OrderByDescending(p => p.PhotoLabel).ThenBy(r => r.UserID).ToList();
List<Photos> temp_photolist = new List<Photos>();
List<Photos> final_photolist = new List<Photos>();
int UserID = -1;
int UserIDCount = 0;
foreach (Photos p in ordered_photolist)
{
if (UserID == -1)
{
UserID = p.UserID;
temp_photolist.Add(p);
UserIDCount++;
}
else
{
if ( UserID == p.UserID )
{
temp_photolist.Add(p);
UserIDCount++;
}
else
{
if ( UserIDCount >= 3 )
{
// add temp_photolist to final list
int index = final_photolist.FindIndex(item => item.UserID == UserID);
if (index == -1)
{
// element does not exists, do what you need
final_photolist.AddRange(temp_photolist);
}
temp_photolist.Clear();
temp_photolist.Add(p);
UserIDCount = 1;
UserID = p.UserID;
}
else
{
temp_photolist.Clear();
UserIDCount = 0;
UserID = -1;
}
}
}
}
I have a problem with getting grouped columns in LINQ.
My class:
public class DTO_CAORAS
{
public int? iORAS_KEY_CON { get; set; }
public int? iMERC_KEY {get;set;}
public double? decD_ORAS_QUA {get;set;}
}
LINQ query:
var results =
from oras in listCAORAS_Delivered
group oras by new
{
oras.iORAS_KEY_CON,
oras.iMERC_KEY
}
into orasGroup
select new
{
decD_ORAS_QUA = orasGroup.Sum(x => x.decD_ORAS_QUA)
};
List results is filled only with one column - decD_ORAS_QUA. I don't know how to get columns, by which query is grouped - IORAS_KEY_CON and iMERC_KEY? I would like to fill results with iORAS_KEY_CON, iMERC_KEY and decD_ORAS_QUA.
Input data:
+---------------+-----------+---------------+
| iORAC_KEY_CON | iMERC_Key | decD_ORAS_QUA |
+---------------+-----------+---------------+
| 1 | 888 | 1 |
| 1 | 888 | 2 |
| 1 | 888 | 4 |
+---------------+-----------+---------------+
Desired output:
+---------------+-----------+---------------+
| iORAC_KEY_CON | iMERC_Key | decD_ORAS_QUA |
+---------------+-----------+---------------+
| 1 | 888 | 7 |
+---------------+-----------+---------------+
To also show the keys:
var results = from oras in listCAORAS_Delivered
group oras by new { oras.iORAS_KEY_CON, oras.iMERC_KEY } into g
select new DTO_CAORAS {
iORAS_KEY_CON = g.Key.iORAS_KEY_CON,
iMERC_KEY = g.Key.iMERC_KEY,
decD_ORAS_QUA = g.Sum(x => x.decD_ORAS_QUA)
};
As you are only grouping one column you can also:
var results = from oras in listCAORAS_Delivered
group oras.decD_ORAS_QUA by new { oras.iORAS_KEY_CON, oras.iMERC_KEY } into g
select new DTO_CAORAS {
iORAS_KEY_CON = g.Key.iORAS_KEY_CON,
iMERC_KEY = g.Key.iMERC_KEY,
decD_ORAS_QUA = g.Sum()
};
Hi I have a List below that needs to be grouped and aggregated using Linq method syntax.
| id |Code|Descr | Number | Expiry |
|---------|----|------|--------|-----------|
| guidId1 | A | Desc1| Number1| 2017-03-18|
| guidId2 | A | Desc1| Number1| 2017-03-18|
| guidId3 | B | Desc2| Number1| 2017-03-18|
| guidId4 | B | Desc2| Number1| 2017-03-18|
| guidId5 | C | Desc3| Number1| 2017-03-18|
| guidId6 | A | Desc1| Number2| 2020-05-20|
| guidId7 | A | Desc1| Number2| 2020-05-20|
| guidId8 | A | Desc1| Number2| 2020-05-20|
| guidId9 | B | Desc2| Number2| 2020-05-20|
| guidId10| C | Desc3| Number2| 2020-05-20|
| guidId11| C | Desc3| Number2| 2020-05-20|
I have tried this but am not sure how to include the count:
myList.GroupBy(s => new { s.Number, s.Code, s.Expiry});
The output I want from the list:
{Code = "A",Descr = "Desc1",Number = "Number1",Expiry = "2017-03-18", Count = 2}
{Code = "B",Descr = "Desc2",Number = "Number1",Expiry = "2017-03-18", Count = 2}
{Code = "C",Descr = "Desc3",Number = "Number1",Expiry = "2017-03-18", Count = 1}
{Code = "A",Descr = "Desc1",Number = "Number2",Expiry = "2020-05-20", Count = 3}
{Code = "B",Descr = "Desc2",Number = "Number2",Expiry = "2020-05-20", Count = 1}
{Code = "C",Descr = "Desc3",Number = "Number2",Expiry = "2020-05-20", Count = 2}
Thanks in advance
You've grouped the Number, Code, and Expiry, but your result needs the Descr as well. You need to include that in your group, then get the count of the groups.
var query =
from s in myList
group 1 by new { s.Code, s.Descr, s.Number, s.Expiry } into g
select new { g.Key.Code, g.Key.Descr, g.Key.Number, g.Key.Expiry, Count = g.Count() };
I have a property database and I am trying to get all properties added by an user. The main table is called 'Property' and there are other tables which are 'PropertyPhotos', 'City' etc. A sample database is as follows:
'Property' table
PropertyId| Area| State| UserId | ...
1 | 1 | 1 | AAA | ...
2 | 2 | 3 | BBB | ...
3 | 1 | 1 | AAA | ...
'PropertyPhotos'
PropertyPhotoId| PropertyId| FileName | MainPic
1 | 1 | x1.jpg | 1
2 | 1 | X2.jpg | 0
3 | 2 | x3.jpg | 1
4 | 3 | x4.jpg | 1
5 | 3 | x5.jpg | 0
6 | 3 | x6.jpg | 0
'AreaLookUp'
AreaLookUpId | AreaDescription
1 | London
2 | Birmingham
3 | Manchester
I am trying to write a LINQ query to get information on property added by a particular user. But I am stuck when trying to retrieve the 'FileName' of the MainPic and also get count. See code below with comments.
So, for the data above, this query should return the following for "UserId = AAA"
PropertyId | ... | MainPicSrc | PhotoCount
1 | ... | x1.jpg | 2
3 | ... | xr4jpg | 3
Please help!
public IEnumerable<PropertyExcerptViewModel> GetAddedPropertyVmByUserId(string userId)
{
var addedProperties = from p in db.Property where p.UserId == userId
join pp in db.PropertyPhotos on p.PropertyId equals pp.PropertyId
join a in db.AreaLookUp on p.Area equals a.AreaLookUpId
select new PropertyExcerptViewModel
{
PropertyId = p.PropertyId,
PropertyType = p.PropertyType,
TransactionType = p.TransactionType,
IsPropertyDisabled = p.IsPropertyDisabled,
IsPropertyVerified = p.IsPropertyVerified,
IsPropertyNotified = p.IsPropertyNotified,
MainPicSrc = pp.FileName, // How to put where condition to only get FileName of just the Main Pic
PhotoCount = pp.Count(), // How to get count of all pics with a particular proprtyId
Price = p.Price,
NoOfBedrooms = p.NoOfBedrooms,
Area = a.AreaLookUpDescription,
ShortDescription = (p.Description.Length > 300) ? p.Description.Substring(0,300) : p.Description
};
return addedProperties.ToList();
}
I think where statement might be easier if you care about clear match
var data=(from c in db.Property from v in db.PropertyPhotos from
n in db.AreaLookUpId
where c.PropertyId==v.PropertyId && c.Area==n.AreaLookUpId && c.UserId=="AAA"
// the rest is your select
PhotoCount = v.Where(j=>j. PropertyId==c.PropertyId).Count()
This also works - I ended up doing it this way
var addedProperties = from p in db.Property
join ppic in db.PropertyPhotos on p.PropertyId equals ppic.PropertyId into pp
join a in db.AreaLookUp on p.Area equals a.AreaLookUpId
join cal in db.CalendarEvent on p.PropertyId equals cal.PropertyId into c
where p.UserId == userId
select new PropertyExcerptViewModel
{
PropertyId = p.PropertyId,
PropertyType = p.PropertyType,
PropertyCategoryDescription = pc.PropertyCategoryDescription,
TransactionType = p.TransactionType,
IsPropertyDisabled = p.IsPropertyDisabled,
IsPropertyVerified = p.IsPropertyVerified,
IsPropertyNotified = p.IsPropertyNotified,
MainPicSrc = pp.Where(e => e.MainPic == true).FirstOrDefault().PhotoLocation,
PhotosCount = pp.Count(),
Price = p.Price,
NoOfBedrooms = p.NoOfBedrooms,
Area = a.AreaLookUpDescription,
ShortDescription = (p.Description.Length > 300) ? p.Description.Substring(0, 300) : p.Description,
LatestCalendarEvent = c.OrderByDescending(e => e.DateSaved).FirstOrDefault()
};
return addedProperties.ToList();