Linq select nested rows - c#

I have the following class:
public class PingtreeTier
{
public BuyerType BuyerType { get; set; }
public int ID { get; set; }
public int MaxRequests { get; set; }
public IEnumerable<PingtreeNode> Nodes { get; set; }
public int Seq { get; set; }
public int Timeout { get; set; }
public bool Weighted { get; set; }
}
As you can see PingtreeTier contains an IEnumerable<PingtreeNode> class. This PingtreeNode class has a property named Status. Using Linq, I need to select only the Tiers/Nodes where PingtreeNode Status = 'Active'.
Anyone help as I'm struggling with the syntax for this.

How about using .Any or .All here:
var results = tiers.Where(t => t.Nodes.Any(n => n.Status == "Active"));
This will select any PingtreeTiers that contain at least one PingTreeNode with Status equal to "Active".
If you wanted to select only PingtreeTiers whose PingTreeNodes are all active, you could use the .All extension method instead:
var results = tiers.Where(t => t.Nodes.All(n => n.Status == "Active"));

Related

nHibernate.IQueryOver removing sub class left join

I have a query with an inner join between two objects (BagDto and ItemDto) where ItemDto also has at least one parent with type of LocationDto. Here are the class definitions:
public class BagDto
{
public int Id { get; set; }
public string Color { get; set; }
public string Type { get; set; }
public DateTime CreatedDate { get; set; }
/* other properties for bag comming from oracle DB */
public IEnumerable<ItemDto> Items { get; set; }
}
public class ItemDto
{
public int Id { get; set; }
public int BagId { get; set; }
public int LocationId { get; set; }
public string Type { get; set; }
public DateTime AddDate { get; set; }
public BagDto Bag { get; set; }
public LocationDto Location { get; set; }
}
public class LocationDto
{
public int Id { get; set; }
public string Name { get; set; }
public double SquareMeters { get; set; }
public string CountyName { get; set; }
public virtual IEnumerable<ItemDto> Items { get; set; }
}
In my query I do not want any kind of Location data to get and only BagDto and ItemDto is really what I would like to query. The mapping of all three objects are okay and I do not want to change those. I also would not like to create inheritance to separate LocationDto out (ie.: ItemDto will not contains LocationDto but ItemWithLocationDto will).
Here is the query:
public IEnumerable<BagDto> GetBagsWithAvailableType()
{
ItemDto itemDtoAlias = null;
Session.QueryOver<BagDto>()
.Where(x.CreatedDate <= DateTime.UtcNow)
.JoinAlias(x => x.Items, () => itemDtoAlias, NHibernate.SqlCommand.JoinType.InnerJoin)
.Where(
() => itemDtoAlias.Type == "A")
.List();
}
Using nHibernate Profiler the following query is generated:
SELECT this_.ID,
this_.COLOR,
this_.TYPE,
this_.CREATEDDATE,
item1_.ID,
item1_.BAG_ID,
item1_.LOCATION_ID,
location2_.ID,
location2_.NAME,
location2_.SQUAREMETERS,
location2_.COUNTYNAME
FROM BAG this_
inner join ITEM item1_
on this_.ID = item1_.BAG_ID
left outer join LOCATION location2_
on item1_.LOCATION_ID = location2_.ID
WHERE (this_.CREATEDDATE <= TIMESTAMP '2021-04-07 16:23:54')
and (item1_.TYPE = 'A')
Anybody knows a way how to get rid of the left outer join related to the LOCATION? I would like to specify this in the query but google all the day for it still no solution. Thanks for the help!
P. S.: writting all this query in plain SQL and call it from the code is a bad practice. Our codeguides are not allowing that.
Without mappings it's not clear why Location is added to the query in a first place. Assuming it's added due to fetch="join" mapping for Location property you can skip it in a query with SelectMode.Skip (available since NHibernate 5.2):
ItemDto itemDtoAlias = null;
Session.QueryOver<BagDto>()
.Where(x.CreatedDate <= DateTime.UtcNow)
.JoinAlias(x => x.Items, () => itemDtoAlias, NHibernate.SqlCommand.JoinType.InnerJoin)
.Fetch(SelectMode.Skip, () => itemDtoAlias.Location)
...
See description of all SelectMode options here

LINQ Selecting a List within a List

I'm trying to fill a list within a list using LINQ to query my database.
The issue I'm facing is that I'm unsure how to select the data into the child list.
When trying to execute the code below, I receive the error
Error 1 Cannot implicitly convert type 'System.Linq.IQueryable' to 'System.Collections.Generic.IEnumerable'. An explicit conversion exists (are you missing a cast?)
The model classes are like so:
public class _LayoutViewModel
{
public List<CallGuideMenuL1> CGL1 { get; set; }
}
public class CallGuideMenuL1
{
public string Area { get; set; }
public List<CallGuideMenuL2> Products { get; set; }
}
public class CallGuideMenuL2
{
public int CallGuideProductId { get; set; }
public string Product { get; set; }
}
And the DB context:
public class CallGuideArea
{
public int CallGuideAreaId { get; set; }
public string Area { get; set; }
public List<CallGuideProduct> CallGuideProducts { get; set; }
}
public class CallGuideProduct
{
public int CallGuideProductId { get; set; }
public string Product { get; set; }
public int CallGuideAreaId { get; set; }
public DateTime Added { get; set; }
public DateTime? Deleted { get; set; }
}
In my controller I'm trying to select the data like so:
_LayoutViewModel vm = new _LayoutViewModel();
vm.CGL1 = from a in db.CallGuideArea
.SelectMany(p => p.CallGuideProducts)
select a;
I'm pretty sure it's the select a; line that's the issue as I need to assign the data back to the properties of both CallGuideMenuL1 and CallGuideMenuL2.
Could anyone point me in the right direction around the right LINQ expression?
vm.CGL1 = db.CallGuideArea.Select(a => new CallGuideMenuL1()
{
Area = a.Area,
Products = a.CallGuideProducts.Select(p => new CallGuideMenuL2()
{
CallGuideProductId = p.CallGuideProductId,
Product = p.Product
}).ToList()
}).ToList();
Probably vm.CGL1 is declared as List so you need to select into List:
vm.CGL1 = (from a in db.CallGuideArea
.SelectMany(p => p.CallGuideProducts)
select a).ToList();
or you will need to project:
vm.CGL1 = (from a in db.CallGuideArea
.SelectMany(p => p.CallGuideProducts)
select new CallGuideMenuL1()
{
Area = a.--some property
...
}).ToList();

Find object with in class using LINQ

I want to return the item that has the profile ID I send. So in order to do this I will need to loop through all of the Items -> WebProproperties -> profile. The Class structure is at the end of the question.
I would rather use LINQ than create a nested foreach. I have been trying to get this to work for more than an hour now. I am stuck.
My first idea was to simply use where. But that doesn't work because you need to have something on the other side that needs to equal.
this.Accounts.items.Where(a => a.webProperties.Where(b => b.profiles.Where(c => c.id == pSearchString)) ).FirstOrDefault();
My second idea was to try using Exists which I don't have much experience with:
Item test = from item in this.Accounts.items.Exists(a => a.webProperties.Exists(b => b.profiles.Exists(c => c.id == pSearchString))) select item;
This doesn't work either:
Could not find an implementation of query pattern for source type 'Bool'
public RootObject Accounts {get; set;}
public class RootObject
{
public string kind { get; set; }
public string username { get; set; }
public int totalResults { get; set; }
public int startIndex { get; set; }
public int itemsPerPage { get; set; }
public List<Item> items { get; set; }
}
public class Profile
{
public string kind { get; set; }
public string id { get; set; }
public string name { get; set; }
public string type { get; set; }
}
public class WebProperty
{
public string kind { get; set; }
public string id { get; set; }
public string name { get; set; }
public string internalWebPropertyId { get; set; }
public string level { get; set; }
public string websiteUrl { get; set; }
public List<Profile> profiles { get; set; }
}
public class Item
{
public string id { get; set; }
public string kind { get; set; }
public string name { get; set; }
public List<WebProperty> webProperties { get; set; }
}
You can use Any() to determine existence. Also, note that many of the extension methods have overloads which take a predicate, including FirstOrDefault():
this.Accounts.items.FirstOrDefault(a => a.webProperties
.Any(b => b.profiles
.Any(c => c.id == pSearchString)));
You are looking for the .Any() operation I think. This will return true/false for whether there are any items matching your query.
For example:
if (this.Accounts.Items.Any(i=>i.webProperties.Any(wp=>wp.profiles.Any(p=>p.id == MySearchId)));
EDIT: You have full answer (was posted while I was composing mine) and as pointed out in comments my answer isn't actually returning your found item, just letting you know whether there is one. You can rework the first .Any to be a .FirstOrDefault to get that match.
E.g.
var result = this.Accounts.Items.FirstOrDefault(i=>i.webProperties.Any(wp=>wp.profiles.Any(p=>p.id == MySearchId)))
You can use the below mentioned code.
var abc = rr.items.Where(p => p.webProperties.Any(c => c.profiles.Any(d => d.id == "1"))).FirstOrDefault();
Just for your reference, your class should look like:
public class RootObject
{
public string kind { get; set; }
public string username { get; set; }
public int totalResults { get; set; }
public int startIndex { get; set; }
public int itemsPerPage { get; set; }
private List<Item> _items=new List<Item>();
public List<Item> items
{
get { return _items; }
set { _items = value; }
}
}

Use IN operator in LINQ

I have List<Candidate> Candidates, List<Seat> Seats
The Model defined as shown below
public class Seat
{
public string CollegeId { get; set; }
public bool isFilled { get; set; }
public string SeatType { get; set; }
public string RollNumber { get; set; }
}
public class Candidate
{
public string RollNumber { get; set; }
public bool isAllotted { get; set; }
public string Quota { get; set; }
public int CandidateRank { get; set; }
public List<OptionPriority> SeatingPriorities { get; set; }
}
public class OptionPriority
{
public string CollegeId { get; set; }
public int PriorityRank { get; set; }
}
I need to filter List<Seat> from List<Seat> Seats where Seats.CollegeId IN List of CollegeID in SeatingPriorities.
// same as EXISTS
Seats.Where(s => SeatingPriorities.Any(sp => sp.CollegeId == s.CollegeId))
Also you can join seatings with seatings priorities:
// same as INNER JOIN
var prioritySeats = from s in Seats
join sp in SeatingPriorities
on s.CollegeId equals sp.CollegeId
select s;
NOTE: Both of queries above will not generate IN clause if you will execute them in LINQ to SQL or LINQ to Entities. IN is generated when you use Contains method of primitive types list:
var ids = SeatingPriorities.Select(sp => sp.CollegeId).ToList();
// same as IN
var prioritySeats = Seats.Where(s => ids.Contains(s.CollegeId));
var results = source.Where(x => SeatingPriorities.Contains(x.CollegeId)).ToList();
You can use Enumerable.Contains to find out the matches like you do with in
var result = lstSeats.Where(s=>SeatingPriorities.Contains(s.CollegeId));
Use Contains to achieve IN functionality in LINQ
You could use Any:
seats.Where(s => SeatingPriorities.Any(i => i.Id == s.CollegeId))
Since Contains only accepts an instance to compare (along with a possible IEqualityComparer<T>), which won't work if OptionPriority isn't an comparable to CollegeId (i.e. a string).

How to use selectmany in linq?

The following is my linq query
var meetingIndividualQuery = meetingsList.SelectMany(o => o.Attendies.Distinct().Where(x => x.CompanyId == company.CompanyId));
I have the following class
public class Meetings
{
public string IndustryCouncil { get; set; }
public string MeetingType { get; set; }
public string MeetingDescription { get; set; }
public string MeetingDate { get; set; }
public string MeetingHours { get; set; }
public string MeetingHourlyValue { get; set; }
public string MeetingTotal { get; set; }
public List<Individual> Attendies { get; set; }
}
With the above query I am getting the correct list of individaul but how I can I use the same query with the same condition to retrieve the list of Meetings. Can you please provide me any code
Following query will return list of meetings, which have at least one attendee with provided company id:
var query = meetingsList.Where(m => m.Attendies.Any(i => i.CompanyId == company.CompanyId));
You can also apply Distinct to Attendies before verifying Any

Categories

Resources