Linq select based on IEnumerable property - c#

I have the following:
IEnumerable<Corporations> Corps = ...
public class Corporation
{
public string CompanyName { get; set; }
public virtual ICollection<Cars> Cars { get; set; }
}
public class Car
{
public int CarID { get; set; }
public string CarName { get; set; }
}
If I have the CarID = 4, how do I get CarName and Company name using linq.
I think I have come close with the .foreach (which is old school?) but get lost closing it:
var result = Corps.Where(cps => cps.Cars != null).ToList()
.ForEach(x => x.Cars.ToList()
.ForEach(cr => cr.CarID == 5)
.Select (#y => new { FoundCorp = x.CompanyName, FoundCar = cr.CarName}....

The code below returns anonymous class instances, with property Cars containing car item matching conditon and Corps property for this car found.
var results = Corps
.SelectMany(corp => corp.Cars, (corps, cars) => new { Corps = corps, Cars = cars })
.Where(item => item.Cars.CarID == 4)
;
foreach (var item in results)
{
Console.WriteLine("Car with id {0} have found in for company {1}", item.Cars.CarID, item.Corps.CompanyName);
}
You might want to replace this anonymous class with some particular that holds only CarName and CompanyName. Just replace the instantiation as below:
var results = Corps
.SelectMany(corp => corp.Cars, (corps, cars) => new SomeResult(corps.CompanyName, cars.CarName))
.Where(item => item.Cars.CarID == 4)
;
This code is safe to number of cars/companies found.

var check = Corporation.SelectMany(p => p.Cars.Where(m => m.CarID == "4").Select(n => new
{
n.CarName,
p.CompanyName
}));

you want to find the corp where any car matches your CarId =>
int carid = 1;
var corp = Corps.FirstOrDefault(corp => corp.Cars.Any(car => car.CarID == carid));
if (Corp != null)
{
Console.WriteLine(Corp.CompanyName);
Console.WriteLine(Corp.Cars.First(car => car.CarID == carid).CarName);
}
As per Smudge's notes, you may consider using a HashTable or similar if you want to ensure your CarId's are unique.

Related

LINQ searching a List that contains a Class with objects

I'm new at C#, I know how to do a LINQ search to a List with one field/type, but not with many types of an object. I created a List
List<Reader> results = new List<Reader>();
That contain this class:
public class Reader
{
public int ID { get; set; }
public string Name { get; set; }
public string Course { get; set; }
public int Grade { get; set; }
public Reader(int id, string name, string course, int grade)
{
ID = id;
Name = name;
Course = course;
Grade = grade;
}
}
I want to search it with LINQ and match the ID and Name of a user that entered the site.
If this two fields are the same I want to take from the List the users Course and Grade.
Any suggestion how to do it ?
A simple Where for condition(s) and Select for representation should do:
List<Reader> results = ...
var data = results
.Where(item => item.ID == userID && item.Name == userName)
// .OrderBy(item => item.Course) // uncomment if you want to order by course
.Select(item => $"Course: {item.Course} Grade: {item.Grade}");
foreach (var record in data)
Console.WriteLine(record);
First, let's assume that you have two variables that hold the values introduced by the user. Those variables are userName of type string and id of type integer. If you just want a variable that holds the course and the Grade you could select a new anonymous type and do the query like this:
var values= results
.Where(item => item.ID == userID && item.Name == userName)
.Select(item => new { Course = item.Course, Grade = item.Grade });
then you could use the values like:
values.Grades
values.Course
var Selecteduser = results.Where(x => x.Name == selectedname && x.ID == ID).ToList();
if (Selecteduser.Count != 0)
{
//found match ..(Selecteduser[0])
string selectedcourse = Selecteduser[0].Course;
int selectedgrade = Selecteduser[0].Grade;
}
else
{
//coudlnt find match
}

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

Using Linq(?) to get a property from a list inside of a list

I need help to select all Titles from List"FeedItem" that is inside of List"Feed" where Feed.Name matches a string from a combobox.
Below is my attempt, which is not succesful, might be on the wrong road.
var loadFeedData = fillFeed.GetAllFeeds();
var filteredOrders =
loadFeedData.SelectMany(x => x.Items)
.Select(y => y.Title)
.Where(z => z.Contains(flow)).ToList();
To understand things better I'll post the Feed.cs code as well.
public class Feed : IEntity
{
public string Url { get; set; }
public Guid Id { get; set; }
public string Category { get; set; }
public string Namn { get; set; }
public string UppdateInterval { get; set; }
public List<FeedItem> Items { get; set; }
}
This is the Whole Code that I'm trying to get working, filling a ListView with the Title, based on the Name of the Listview with Feed.Name that I select.
private void listFlow_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
listInfo.Items.Clear();
listEpisode.Items.Clear();
if (listFlow.SelectedItem != null)
{
string flow = listFlow.SelectedItem.ToString();
var loadFeedData = fillFeed.GetAllFeeds();
var filteredOrders = loadFeedData
.Where(f => f.Name == myStringFromComboBox)
.SelectMany(f => f.Items)
.Select(fi => fi.Title);
listEpisode.Items.Add(filteredOrders);
}
}
- Posted whole code to clear out some ??
loadFeedData
.Where(f => f.Name == myStringFromComboBox)
.SelectMany(f => f.Items)
.Select(fi => fi.Title);
I believe you are looking for:
List<string> titles = loadFeedData.Where(f => f.Name == "SomeName")
.SelectMany(f => f.Items.Select(subItem => subItem.Title))
.ToList();
First you will filter your main list loadFeedData based on Name
Then select Title from List<FeedItem>
Later flatten your Titles, using SelectMany to return an IEnumerable<string>
Optional, call ToList to get a List<string> back.
If I understand you correctly, you want to use this one:
var filteredOrders = loadFeedData.Where(x => x.Name == flow)
.SelectMany(x => x.Items)
.Select(x => x.Title).ToList();
This will give you all FeedItem items inside all Feed things, which have Feed.Name == flow.

Getting properties from a child

I have the following entities:
public class Parent
{
int Id { get; set; }
string ParentName { get; set; }
List<Child> Children { get; set; }
}
public class Child
{
int Id { get; set; }
string ChildName { get; set; }
}
and the following dto:
public class ParentDTO
{
int Id { get; set; }
List<string> ChildrenNames { get; set; }
}
using QueryOver code below I can get the Parent values
ParentDTO result = null;
Parent parentAlias = null;
Child childAlias = null;
var query = session.QueryOver(() => parentAlias)
.JoinAlias(() => parentAlias.Children, () => childAlias, JoinType.LeftOuterJoin)
.SelectList(list => list.Select(c => c.Id).WithAlias(() => result.Id)
.Select(c => c.ParentName).WithAlias(() => result.Name)
//this part does not work
.Select(c => c.Children .Select(v => v.ChildName)).WithAlias(() => result.ChildrenNames)
//
)
.TransformUsing(Transformers.AliasToBean<ParentDTO>());
return query.List<ParentDTO>();
However I cant seem to be able to project the list of childName values into my ChildrenNames collection.
Any ideas?
As some guys said in comments, you need to do two queries. Using linq, you could try something like this:
// get the parent Ids
var parentIds = session.Query<Parent>().Select(c => c.Id).ToList();
// get the childNames
var childNames = session.Query<Child>()
.Where(x => parentIds.Contains(x.ParentId)) // get on the child from parents query
.Select(x => new {x.Name, x.ParentId}) // get only the properties you need
.ToList(); // list of anon objects
// loop in memory between parentIds filling the corresponding childNames
var result = parentIds.Select(parentId => new ParentDTO()
{
Id = parentId,
ChildrenNames = childNames.Where(x => x.ParentId == parentId).ToList()
}).ToList();
I am not sure if it works, but you could try this in a single query:
var query = from p in session.Query<Parent>()
let names = p.Children.Select(c => c.ChildName).ToList()
select new ParentDTO()
{
Id = o.Id,
ChildrenNames = names
};
return query.Tolist();
Obs: I did not test it.

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

Categories

Resources