I would like to get the count of a number of entity tables and assign them to a single object which holds the counted values.
I am using a union because I want to execute a single query against the database.
I have written the following code but this will return a separate counts view model for each group by, instead Id like to assign the values to the properties of a single counts view model.
var counts =
_db.Departments.All()
.Select(c => new {key = 1, count = 0})
.Union(_db.Students.All().Select(c => new {key = 2, count= 0}))
.GroupBy(c=>c.key)
.Select(x => new CountsVm()
{
DepartmentCount = x.Count(d => d.key == 1),
StudentCount = x.Count(s => s.key == 2)
});
public class CountsVm
{
public int StudentCount { get; set; }
public int DepartmentCount { get; set; }
}
Here is a solution which will produce one query
var countsQuery =
_db.Departments.All()
.Select(p => new { key = 1, count = 0 })
.Union(_db.Students.All().Select(p => new { key = 2, count = 0 }))
.GroupBy(p => p.key)
.Select(p => new { key = p.Key, count = p.Count() }).ToList();
var counts = new CountsVm()
{
DepartmentCount =
countsQuery.Where(p => p.key == 1)
.Select(p => p.count)
.FirstOrDefault(),
StudentCount =
countsQuery.Where(p => p.key == 2)
.Select(p => p.count)
.FirstOrDefault()
};
Do you just need to call count on each entry table separately?
var counts = new CountsVm()
{
DepartmentCount = _db.Departments.All().Count(),
StudentCount = _db.Students.All().Count()
};
If I understand it correctly you could do something like: (i've done only using linq, but the return null inside a select it's not a good practice). A foreach would server you better)
var countsVm = new CountsVm(){
DepartmentCount = 0,
StudentCount = 0
};
var counts =
_db.Departments.All()
.Select(c => new {key = 1, count = 0})
.Union(_db.Students.All().Select(c => new {key = 2, count= 0}))
.GroupBy(c=>c.key)
.Select(x => {
countsVm.DepartmentCount += x.Count(d => d.key == 1);
countsVm.StudentCount += x.Count(s => s.key == 2);
return null;
});
public class CountsVm
{
public int StudentCount { get; set; }
public int DepartmentCount { get; set; }
}
Try to remove All from query and run FirstOrDefault()
var counts =
_db.Departments.
.Select(c => new {key = 1, count = 0})
.Union(_db.Students.Select(c => new {key = 2, count= 0}))
.GroupBy(c=>c.key)
.Select(x => new CountsVm()
{
DepartmentCount = x.Count(d => d.key == 1),
StudentCount = x.Count(s => s.key == 2)
}).FirstOrDefault();
public class CountsVm
{
public int StudentCount { get; set; }
public int DepartmentCount { get; set; }
}
Related
So I am trying to group a list of ErrorItem into a list of ValidationFormatErrorDTO, depending on either the FieldType or the ValidationFormat.
The goal is to have a list of ValidationFormatErrorDTO containing only one type of errors.
The final object. So I am trying to have a list of it:
public class ValidationFormatErrorDTO
{
public ValidationFormat ValidationFormat { get; set; }
public FieldType FieldType { get; set; }
public List<ValidationFormatErrorItemDTO> ErrorItems { get; set; }
}
public class ValidationFormatErrorItemDTO
{
public int LineNumber { get; set; }
public string LineValue { get; set; }
}
Examples of error objects:
example 1:
var error = new ErrorItem
{
LineNumber = 2,
LineValue = "Test",
FieldType = FieldType.DateTime,
ValidationFormat = null
};
example 2:
error = new ErrorItem
{
LineNumber = 11,
LineValue = "john.doe.test.com",
ValidationFormat = ValidationFormat.Email,
FieldType = null
};
example 3:
error = new ErrorItem
{
LineNumber = 32,
LineValue = "1212",
ValidationFormat = ValidationFormat.PhoneNumber,
FieldType = null
};
And from here I'm stuck.
I've tried this:
var test = tempListErrors.GroupBy(x => x.ValidationFormat)
.Select(y => new ValidationFormatErrorDTO
{
ValidationFormat = y.Key,
ErrorItems = ??
}).ToList();
But first of all it means I should do the same for errors based on the FieldType. Which would give me 2 lists of ValidationFormatErrorDTO I would the have to join into 1 list.
And second, with this method I'm stuck with an IGrouping<ValidationFormat, ErrorItem> I don't know how to deal with.
I any of you think about how to do it with from where I am right now, or think about a better solution, that would be awesome!
Thanks for your time!
EDITS:
So, according to #Ashkan's answer, I would have this:
var formatErrors = tempListErrors.GroupBy(x => x.ValidationFormat)
.Select(y => new ValidationFormatErrorDTO
{
ValidationFormat = y.Key,
ErrorItems = y.Select(x => new ValidationFormatErrorItemDTO
{
LineNumber = x.LineNumber,
LineValue = x.LineValue
}).ToList()
}).ToList();
var fieldTypeErrors = tempListErrors.GroupBy(x => x.FieldType)
.Select(y => new ValidationFormatErrorDTO
{
FieldType = y.Key,
ErrorItems = y.Select(x => new ValidationFormatErrorItemDTO
{
LineNumber = x.LineNumber,
LineValue = x.LineValue
}).ToList()
}).ToList();
Any idea on how I can now merge those two?
Or how to group by both ValidationFormatand FieldType to get only one list?
Something like this?
var both = tempListErrors.GroupBy(x => new { x.ValidationFormat, x.FieldType })
.Select(y => new ValidationFormatErrorDTO
{
ValidationFormat = y.Key.ValidationFormat,
FieldType = y.Key.FieldType,
ErrorItems = y.Select(x => new ValidationFormatErrorItemDTO
{
LineNumber = x.LineNumber,
LineValue = x.LineValue
}).ToList()
}).ToList();
IGrouping I don't know how to deal with.
According to this specs it means that
Represents a collection of objects that have a common key
So from that point, you can get a list of ErrorItems like this
ErrorItems = group.Select(item => new ValidationFormatErrorItemDTO
{
LineNumber = item.LineNumber,
LineValue = item.LineValue
}).ToList()
Updated
var test = tempListErrors.GroupBy(p => new { p.ValidationFormat, p.FieldType})
.Select(group => new ValidationFormatErrorDTO
{
ValidationFormat = group.Key.ValidationFormat,
ErrorItems = group.Select(item => new ValidationFormatErrorItemDTO
{
LineNumber = item.LineNumber,
LineValue = item.LineValue
}).ToList()
}).ToList();
as y is the each group, so you can perform a .Select() on y to get a List<ValidationFormatErrorItemDTO>:
var test = tempListErrors.GroupBy(x => x.ValidationFormat)
.Select(y => new ValidationFormatErrorDTO
{
ValidationFormat = y.Key,
ErrorItems = y.Select(x => new ValidationFormatErrorItemDTO
{
LineNumber = x.LineNumber,
LineValue = x.LineValue
}).ToList()
}).ToList();
I have the following class:
public class Relation {
public Int32 SourceId { get; set; }
public Int32 TargetId { get; set; }
}
And the following list:
List<Relation> relations = service.GetRelations();
I need to select the SourceIds which are related to ALL targets.
So, given the following example with pairs (SourceId, TargetId):
(1, 1), (1, 2), (2, 1), (3, 2)
In this case TargetId can be 1 or 2.
And the only SourceId that is related to all TargetIds (1, 2) is SourceId 1.
SourceId 2 is only related to TargetId 1 and SourceId 3 is only related to TargetId 2.
How can I do this?
You need to collect all possible targets ids:
var input = new []
{
new Relation(1, 1),
new Relation(1, 2),
new Relation(2, 1),
new Relation(3, 2),
};
var allTargetId = input.Select(x => x.TargetId).Distinct().ToArray();
Then group by source id and in each group check that all group members presented in allTargetId:
var result = input.GroupBy(x => x.SourceId, x => x.TargetId)
.Where(g => allTargetId.All(x => g.Contains(x)))
.Select(g => g.Key)
.ToArray();
Note: to make this code work I've added a constructor to your Relation class and it looks like
public class Relation
{
public Relation(int sourceId, int targetId)
{
SourceId = sourceId;
TargetId = targetId;
}
public Int32 SourceId { get; set; }
public Int32 TargetId { get; set; }
}
EDIT
To get Relation's you can use this query:
var result = input.GroupBy(x => x.SourceId)
.Where(g => allTargetId.All(x => g.Select(y => y.TargetId).Contains(x)))
.SelectMany(g => g)
.ToArray();
Please note that I've tested it only with linq2objects so I'm not sure how it will be translated to SQL
The following code does what you asked for. It has a form of unit test so you can check different scenarios
[Fact]
public void FindSourcesThatTargetAll()
{
var list = new List<Relation>
{
new Relation(1, 1), new Relation(1, 2), new Relation(2, 1), new Relation(3, 2)
};
var allTargets = list.Select(x => x.TargetId).Distinct().OrderBy(x=>x).ToList();
var dict = list.GroupBy(x => x.SourceId).ToDictionary(x => x.Key,
grouping => grouping.Select(y => y.TargetId).Distinct().OrderBy(x=>x).ToList());
var sourcesThatTargetAll = dict.Where(x => x.Value.Count == allTargets.Count).Select(x => x.Key).ToList();
Assert.Single(sourcesThatTargetAll);
Assert.Equal(1, sourcesThatTargetAll.First());
}
Basically, I did:
Find all the targets.
For every source find all targets (distinct is important) and group it by the source in the dictionary (dict variable)
From the above dictionary select all source which matches all targets (count in the example is enough, but you can make a more complicated comparison)
A simple way to achieve this would be to group the records by TargetId, and then find an intersection of all the SourceId
var groups = relations.GroupBy(r => r.TargetId).ToArray();
if (groups.Length > 0) {
var set = new HashSet<int>(groups[0]);
for (int i = 1; i < groups.Length; ++i)
set.IntersectWith(groups[i].Select(r => r.SourceId));
}
At the end of this set will contain all the SourceIds that are related to all TargetIds
public class Relation
{
public Int32 SourceId { get; set; }
public Int32 TargetId { get; set; }
}
public Int32?[] FindRelation(Relation[] relations)
{
List<Int32?> sourceIds = new List<int?>;
var countOfTargets = relations.Select(x => x.TargetId).Distinct().Count();
var relationsGroupedBySource = relations.GroupBy(x => x.SourceId);
foreach (var group in relationsGroupedBySource)
{
var distinctGroup = group.Distinct();
if (distinctGroup.Count() == countOfTargets)
{
sourceIds.Add(distinctGroup.Select(x => x.SourceId).First());
}
}
return sourceIds.ToArray();
}
public void Test()
{
Relation[] relations = {
new Relation() { SourceId = 1, TargetId = 1 },
new Relation() { SourceId = 1, TargetId = 2 },
new Relation() { SourceId = 2, TargetId = 1 },
new Relation() { SourceId = 3, TargetId = 2 }
};
var sourceIds = FindRelation(relations);
}
I have fourtables:
CL_ProductType
CL_InsuranceProduct
PR_Product
PR_ProductInsuranceProduct (aggregation table for PR_Product and CL_InsuranceProduct)
I need left join for PR_ProductInsuranceProduct and I've done it with SelectMany() selector.
The problem is that this query has groupBy method, and I need to extract the max(ID_ProductInsuranceProduct).
My question is: How to extract in .SelectMany() the highist value of ID_ProductInsuranceProduct?
SQL that works:
select p.ID_Product,p.Name, p.Code, p.InProduction, MAX(pip.ID_ProductInsuranceProduct)
from PR_Product p
join CL_ProductType pt ON p.ID_ProductType = pt.ID_ProductType
left join PR_ProductInsuranceProduct pip ON p.ID_Product = pip.ID_Product
join CL_InsuranceProduct ip ON pip.ID_InsuranceProduct = ip.ID_InsuranceProduct
GROUP BY p.ID_Product,p.Name, p.Code, p.InProduction
My code in C# and LINQ Lambda:
var query = DBContext.PR_Product
.Where(m => m.Active)
.Where(nameFilter)
.Where(activationDateFilter)
.Where(closureDateFilter)
.Where(productTypeFilter)
.Where(subgroupFilter)
.Where(inproductionFilter)
.Where(answerFilter)
.Where(insuranceProductFilter)
.Where(excludePidsFilter)
.Join(DBContext.CL_ProductType, p => p.ID_ProductType, pt => pt.ID_ProductType,
(p, pt) => new { p, pt = pt.Name })
.GroupJoin(DBContext.PR_ProductInsuranceProduct,
p => p.p.ID_Product,
pip => pip.ID_Product,
(p1, pip) => new { Products = p1, ProductInsuranceProduct = pip })
.SelectMany
(
x => x.ProductInsuranceProduct.DefaultIfEmpty(),
(x, y) => new
{
x.Products.p.ID_Product,
x.Products.p.Name,
x.Products.p.Code,
x.Products.p.ActivationDate,
x.Products.p.ClosureDate,
x.Products.pt,
x.Products.p.InProduction,
//Here I want to fill in to my custom property max for ID_ProductInsuranceProduct, MaxId is a custom property in a model
x.Products.p.MaxId = x.ProductInsuranceProduct.Max(pip => pip.ID_ProductInsuranceProduct)
})
.GroupBy(x =>
new
{
x.ID_Product,
x.Name,
x.Code,
x.ActivationDate,
x.ClosureDate,
x.pt,
x.InProduction,
});
I assume, beacause it's a SelectMany, that my code returns "flatten" data into one single table, therefore, my method Max, its input is bad, because its not a collection?
Can I do left join in linq with just .Select()?
My continuation of the code, when I execute the query:
count = query.Count();
var list = query
.OrderBy(x => x.FirstOrDefault().Code)
.DoPaging(pageSize, pageIndex)
.ToList();
List<PR_Product> products =
(from m in list
select new PR_Product
{
ID_Product = m.Key.ID_Product,
Name = m.Key.Name,
Code = m.Key.Code,
ActivationDate = m.Key.ActivationDate,
ClosureDate = m.Key.ClosureDate,
ActivationDateString = m.Key.ActivationDate.ToString("d", new CultureInfo(DALParams.LCID, false)),
ClosureDateString = m.Key.ClosureDate.ToString("d", new CultureInfo(DALParams.LCID, false)),
ProductType = m.Key.pt,
InProduction = m.Key.InProduction
//MaxId = implemention...
}).ToList();
Given the following objects:
public class PR_Product
{
public int ID_Product { get; set; }
public string Name { get; set; }
public string Code { get; set; }
public bool InProduction { get; set; }
}
public class PR_ProductInsuranceProduct
{
public int ID_ProductInsuranceProduct { get; set; }
public int ID_Product { get; set; }
}
I've create in memory collections to demonstrate how to extract max(property) from a left join in LINQ with a lambda expression:
var product = new List<PR_Product>
{
new PR_Product { ID_Product = 1, Name = "TestName1", Code = "TestCode1", InProduction = true },
new PR_Product { ID_Product = 2, Name = "TestName2", Code = "TestCode3", InProduction = true },
new PR_Product { ID_Product = 3, Name = "TestName3", Code = "TestCode3", InProduction = true }
};
var productInsurance = new List<PR_ProductInsuranceProduct>
{
new PR_ProductInsuranceProduct { ID_ProductInsuranceProduct = 111, ID_Product = 1 },
new PR_ProductInsuranceProduct { ID_ProductInsuranceProduct = 222, ID_Product = 1 },
new PR_ProductInsuranceProduct { ID_ProductInsuranceProduct = 333, ID_Product = 3 },
};
var result = product
.GroupJoin(productInsurance,
prProduct => prProduct.ID_Product,
insuranceProduct => insuranceProduct.ID_Product,
(prProduct, insuranceProduct) => new { prProduct, insuranceProduct })
.SelectMany(arg => arg.insuranceProduct.DefaultIfEmpty(), (prProduct, insuranceProducts) => new { prProduct })
.GroupBy(arg => new { arg.prProduct.prProduct.ID_Product, arg.prProduct.prProduct.Name, arg.prProduct.prProduct.Code, arg.prProduct.prProduct.InProduction})
.Select(grouping => new
{
grouping.Key.ID_Product,
grouping.Key.Name,
grouping.Key.Code,
Max_ID_ProductInsuranceProduct = grouping.FirstOrDefault()?.prProduct.insuranceProduct.DefaultIfEmpty().Max(insuranceProduct => insuranceProduct?.ID_ProductInsuranceProduct)
});
Console.WriteLine(JsonConvert.SerializeObject(result, Formatting.Indented));
Hope this helps.
Object
namespace Example
{
public class ContractorAddValue
{
public Member Member { get; set; }
public List<Addresses> Addresses { get; set; }
public ICommand AddAddress { get; set; }
}
public class Addresses
{
public MemberAddress MemberAddress { get; set; }
public ICommand EditAddress { get; set; }
}
}
Query
public ObservableCollection<ContractorAddValue> GetContractorsOrderByCity()
{
var allContractors = (from c in db.Member where c.IsContrator == true select c).ToList();
//var allContractors2 = db.Member .Include(c => c.MemberAddress).SelectMany(c => c.MemberAddress).OrderBy(c => c.City).Select(c => c.Member ).ToList();
//var allContractors = (from c in db.Member where c.IsContrator == true select c).OrderBy(c => c.MemberAddress.OrderBy(x => x.City)).ToList(); <= dosent work
var listContractorAddValue = new ObservableCollection<ContractorAddValue>();
foreach (var i in allContractors)
{
var adressList = db.MemberAddress.Where(x => x.MemberId == i.MemberId).OrderBy(x => x.City).ToList();
ContractorAddValue contractorAddValue = new ContractorAddValue();
contractorAddValue.Member = i;
contractorAddValue.AddAddress = new BaseCommand(() => ContractorsViewModel.SendAddress(i.MemberId ));
contractorAddValue.Addresses = new List<Addresses>();
foreach (var a in adressList)
{
Addresses memberAdress = new Addresses();
memberAdress.MemberAddress = a;
memberAdress.EditAddress = new BaseCommand(() => ContractorsViewModel.SendEditAddress(a.MemberAddressId , i.MemberId ));
contractorAddValue.Addresses.Add(memberAdress);
}
listContractorAddValue.Add(contractorAddValue);
}
return listContractorAddValue;
}
allContractors2 - the order by works, but I retrieve repeating Members. In this approach I tried to use .Distinct() after Select(c => c.Member) but it doesn't work (the whole query stops working).
My goal is to make an order by MemberAddress.City
Thanks in advance!
I think that this code will work but you need to redefine the Equals method of the ContractorAddValue class.
I added one if statement when you want to add contractorAddValue to the list. First you need to check if your list contains that object. If not you add the object to the list. If yes you need to find that object and merge its addresses list with addresses list from the object you want to add.
public ObservableCollection<ContractorAddValue> GetContractorsOrderByCity()
{
var allContractors = (from c in db.Member where c.IsContrator == true select c).ToList();
//var allContractors2 = db.Member .Include(c => c.MemberAddress).SelectMany(c => c.MemberAddress).OrderBy(c => c.City).Select(c => c.Member ).ToList();
//var allContractors = (from c in db.Member where c.IsContrator == true select c).OrderBy(c => c.MemberAddress.OrderBy(x => x.City)).ToList(); <= dosent work
var listContractorAddValue = new ObservableCollection<ContractorAddValue>();
foreach (var i in allContractors)
{
var adressList = db.MemberAddress.Where(x => x.MemberId == i.MemberId).OrderBy(x => x.City).ToList();
ContractorAddValue contractorAddValue = new ContractorAddValue();
contractorAddValue.Member = i;
contractorAddValue.AddAddress = new BaseCommand(() => ContractorsViewModel.SendAddress(i.MemberId ));
contractorAddValue.Addresses = new List<Addresses>();
foreach (var a in adressList)
{
Addresses memberAdress = new Addresses();
memberAdress.MemberAddress = a;
memberAdress.EditAddress = new BaseCommand(() => ContractorsViewModel.SendEditAddress(a.MemberAddressId , i.MemberId ));
contractorAddValue.Addresses.Add(memberAdress);
}
if(!listContractorAddValue.Contains(contractorAddValue)){
listContractorAddValue.Add(contractorAddValue);
} else {
var contAddValue = listContractorAddValue.First(l => l.Equals( contractorAddValue));
contAddValue.Addresses.AddRange(contractorAddValue.Addresses);
}
}
return listContractorAddValue;
}
The result set below:
ServiceName Ping Desc LogName BaseUrl EnvName
IntegrationServices.BillingInstructionsService /IntegrationServices/BillingInstructionsService.svc/Rest/Ping BillingInstructionsService IntegrationServices.BillingInstructionsServices https://icrDev.xxx.com Dev
IntegrationServices.BillingInstructionsService /IntegrationServices/BillingInstructionsService.svc/Rest/Ping BillingInstructionsService IntegrationServices.BillingInstructionsServices https://IUTD01.xxx.com DevUnitTest
IntegrationServices.BillingInstructionsService /IntegrationServices/BillingInstructionsService.svc/Rest/Ping BillingInstructionsService IntegrationServices.BillingInstructionsServices https://ickd01.xxx.com DevClock
IntegrationServices.BillingInstructionsService /IntegrationServices/BillingInstructionsService.svc/Rest/Ping BillingInstructionsService IntegrationServices.BillingInstructionsServices https://icd01.xxx.com DevConv
is returned from the linq query below my needs can be either filtered(ServiceId) or unfiltered ...:
var data = contextObj.ServiceMonitorMappings
.Where(r => r.ServiceId == 33)
.Select(x => new
{
ServiceName = x.Service.Name,
Ping = x.Service.PingUrl,
Desc = x.Service.Description,
LogName = x.ServiceLoggingName.LoggingName,
BaseUrl = x.ServiceBaseUrl.ServiceBaseUrl1,
EnvName = x.ServiceEnvironment.Name
});
ServiceMonitorMapping looks like this:
public partial class ServiceMonitorMapping
{
public int Id { get; set; }
public int ServiceEnvironmentId { get; set; }
public int ServiceId { get; set; }
public int ServiceLoggingNameId { get; set; }
public int ServiceBaseUrlId { get; set; }
public virtual Service Service { get; set; }
public virtual ServiceLoggingName ServiceLoggingName { get; set; }
public virtual ServiceBaseUrl ServiceBaseUrl { get; set; }
public virtual ServiceEnvironment ServiceEnvironment { get; set; }
}
I was trying to get BaseUrl and EnvName to return as an enumerable collection so that I wouldn't have 4 records but 1 with the last 2 columns containing a list of BaseUrl and EnvName, however I cannot find a way to do this. So I am stuck with 4 records as opposed to 1. Does not seem to be ideal to me.
So my question is this, is it possible to return just 1 row with the last 2 columns being a collection so that I have "item item item item List<> List<>"?
Any help would be appreciated.
var data = contextObj.ServiceMonitorMappings
.Where(r => r.ServiceId == 33)
.Select(x => new
{
Key = new {ServiceName = x.Service.Name,
Ping = x.Service.PingUrl,
Desc = x.Service.Description,
LogName = x.ServiceLoggingName.LoggingName};
BaseUrl = x.ServiceBaseUrl.ServiceBaseUrl1,
EnvName = x.ServiceEnvironment.Name
})
.GroupBy(x => x.Key)
.Select(g => new
{
ServiceName = g.Key.ServiceName,
Ping = g.Key.Ping,
Desc = g.Key.Desc,
LogName = g.Key.LogName,
BaseUrls = g.Select(x => x.BaseUrl).ToList(),
EnvNames = g.Select(x => x.EnvName ).ToList();
})
Although tolanj's answer is rather good, I believe it is not the easiest approach. You could use just Select after grouping to simplify your query:
var data = contextObj.ServiceMonitorMappings
.GroupBy(r => r.ServiceId)
.Where(r => r.Key == 33)
.Select(x => new
{
ServiceName = x.First().Service.Name,
Ping = x.First().Service.PingUrl,
Desc = x.First().Service.Description,
LogName = x.First().ServiceLoggingName.LoggingName,
BaseUrl = x.Select(y => y.ServiceBaseUrl.ServiceBaseUrl1).ToList(), //ToList is optional
EnvName = x.Select(y => y.ServiceEnvironment.Name).ToList() //ToList is optional
});
At first, I didn't notice that this is a DB query through LINQ to SQL. In order to use this approach and not loose the performance due to downloading whole table you can try it like this:
var data = contextObj.ServiceMonitorMappings
.Where(r => r.ServiceId == 33)
.AsEnumerable() //AsEnumerable after Where to apply filter on the DB query
.GroupBy(x => 1) //data already filtered, only one group as a result
.Select(x => new
{
ServiceName = x.First().Service.Name,
Ping = x.First().Service.PingUrl,
Desc = x.First().Service.Description,
LogName = x.First().ServiceLoggingName.LoggingName,
BaseUrl = x.Select(y => y.ServiceBaseUrl.ServiceBaseUrl1).ToList(), //ToList is optional
EnvName = x.Select(y => y.ServiceEnvironment.Name).ToList() //ToList is optional
});
I hope that you understand your needs; I solved with this way:
var query = contextObj.ServiceMonitorMappings
.Where(r => r.ServiceId == 33)
.Select(d => new {
BaseUrl = d.ServiceBaseUrl.ServiceBaseUrl1,
EnvName = d.ServiceEnvironment.Name})
.Aggregate((d1, d2) =>
new {
BaseUrl = d1.BaseUrl + ", " + d2.BaseUrl,
EnvName = d1.EnvName + ", " + d2.EnvName
});
This is the result:
BaseUrl
https://icrDev.xxx.com, https://IUTD01.xxx.com, https://ickd01.xxx.co, https://icd01.xxx.com
EnvName
Dev, DevUnitTest, DevClock, DevConv
EDIT:
I've changed my query to return your needed result:
var query = contextObj.ServiceMonitorMappings
.Where(r => r.ServiceId == 33)
.Select(d => new {
BaseUrl = d.ServiceBaseUrl.ServiceBaseUrl1,
EnvName = d.ServiceEnvironment.Name})
.Aggregate(
//initialize the accumulator
new { BaseUrl = new List<string>(), EnvName = new List<string>() },
(acc, next) => //accumulator and nextItem
{
acc.BaseUrl.Add(next.BaseUrl);
acc.EnvName.Add(next.EnvName);
return acc;
});