LINQ joining values from different classes - c#

I am new to LINQ and sorry if my question have been asked
I have 2 classes
public class Person
{
int ID {get;set;}
string FirstName {get;set;}
string LastName {get;set;}
}
and
public class House
{
int ID {get;set;}
string Address {get;set;}
string ZipCode {get;set;}
int PersonId {get;set;}
}
I am saving the list of houses in a IEnumerable List
IEnumerable<House> ListHouses = GetAllHouses();
GetAllHouses return the list of houses from the database
I want to use Lamda select in LINQ in order to do the following
var st = ListHouses .Select(h => new
{
id = h.ID,
Address= h.Address,
Zip= h.ZipCode ,
PersonFirstName = GetPersonByID(h.PersonId ).FirstName,
PersonLastname = GetPersonByID(h.PersonId ).lastname
});
Where GetPersonByID returns an object of Type Person that has the given ID. and then I take his first name and last name.
My question is this:
Instead of Getting the Person 2 times for the variables (personFirstName and PersonLastName) Is there a way I can get it one time and then used it. Something like
PersonForId = GetPersonByID(h.PersonId)
PersonFirstName = PersonLastName.FirstName,
PersonLastname = PersonLastName.lastname
I'm looking for something similar to Join in SQL where you join a value from another table.
Thanks you very much for any help

You're extremely close! Using your code (and making all properties on House and Person public), here is a method using the LINQ Join method:
var st = GetAllHouses().Join(GetAllPersons(),
outerKey => outerKey.PersonId,
innerKey => innerKey.ID,
(house, person) => new
{
house.ID,
house.Address,
house.ZipCode,
PersonFirstName = person.FirstName,
PersonLastname = person.LastName
});
Note: I would recommend the GetAllPersons() and the GetAllHouses() methods return IQueryable rather than IEnumerable. Doing so will build the expression (including the join), which means LINQ-to-SQL (or Entities) will build a proper SQL statement with the JOIN included, instead of enumerating the collections and then joining.
Additional information on such can be found here: Returning IEnumerable<T> vs. IQueryable<T>

using System;
using System.Linq;
class Customer
{
public int ID { get; set; }
public string Name { get; set; }
}
class Order
{
public int ID { get; set; }
public string Product { get; set; }
}
class Program
{
static void Main()
{
// Example customers.
var customers = new Customer[]
{
new Customer{ID = 5, Name = "Sam"},
new Customer{ID = 6, Name = "Dave"},
new Customer{ID = 7, Name = "Julia"},
new Customer{ID = 8, Name = "Sue"}
};
// Example orders.
var orders = new Order[]
{
new Order{ID = 5, Product = "Book"},
new Order{ID = 6, Product = "Game"},
new Order{ID = 7, Product = "Computer"},
new Order{ID = 8, Product = "Shirt"}
};
// Join on the ID properties.
var query = from c in customers
join o in orders on c.ID equals o.ID
select new { c.Name, o.Product };
// Display joined groups.
foreach (var group in query)
{
Console.WriteLine("{0} bought {1}", group.Name, group.Product);
}
}
}
Output
Sam bought Book
Dave bought Game
Julia bought Computer
Sue bought Shirt

Related

Add element to a List when delcaring new object

Is there a way to add elements to a List when doing this:
var Foo = new MyClass() {
PropertyList = MyList,
Id = Id,
}
I would like to add elements to PropertyList. For example would be the same as: MyList.Add()
The problem is that i do not have a list called MyList but i rather have elements that i want to append to PropertyList
Updating code based on comments:
var result1 = await query
.GroupBy(c => new {
c.CommissionId, c.ActivityId
})
.Select(grp => new RegistrationStatisticViewModel() {
CommissionId = grp.Key.CommissionId,
CommissionCode = grp.First().Commission.Code,
CommissionDescription = grp.First().Commission.Description,
MinuteWorked = grp.Sum(c => c.MinuteWorked),
ActivityId = grp.Key.ActivityId,
ActivityCode = grp.First().Activity.Code,
ActivityDescription = grp.First().Activity.Description,
})
.ToListAsync();
var grps = from d in result1
group d by d.CommissionId
into grp
select new RegistrationStatisticViewModel() {
CommissionId = grp.Key,
ActivityList = new List < Activity > {
new Activity {
//ActivityId = grp.Select(d => d.ActivityId),
//Code = grp.Select(d => d.ActivityCode),
//Description = grp.Select(d => d.ActivityDescription),
}
},
CommissionCode = grp.First().CommissionCode,
CommissionDescription = grp.First().CommissionDescription,
MinuteWorked = grp.First().MinuteWorked
};
return grps;
To give context:
forget the result1 is just some data i retrieve from my database
Commission is one class and contains:
CommissionId
Code
Description
Activity is one class and contains:
ActivityId ==> type GUID
Code ==> type string
Description ==> type string
Now the var = grps is a LINQ that gets the data and then instatiates a new object (class) new RegistrationStatisticViewModel()
So the tricky part we were discussing before is when i populate ActivityList with multiple activities.
When populating the list if i use .First() or .Select() i would only get one instance and therfore the list would only have one activity.
It worked when using .ToArray() for example if i replace ActivityList with just the ActivityId of type string (so a new property on RegistrationStatisticViewModel that is not a list anymore):
I can do this ActivityId = grp.Select(d2 => d2.ActivityId).ToArray()
And it will give me an array of all the ActivityId linked to that commissionId
I am sorry if this is confusing but it is for me as well. I would thank you if you could help me. No worries if you can't you have already give me very helpful answers, so i thank you for that!
Based on your remarks, I believe this is what you are trying to achieve:
public class PersonContainer
{
public IList<Person> Persons { get; set; }
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
var personContainer = new PersonContainer
{
Persons = new List<Person>
{
new Person
{
Name = "John Doe",
Age = 28,
},
new Person
{
Name = "Jane Doe",
Age = 27,
},
}
};
Here, the Persons property of PersonContainer is initialized and populated with Person elements during instantiation.

Selecting on document "outside" of join while filtering on documents "within" join?

I have two IMongoCollections holding documents of type Person and Animal respectively.
public class Person
{
public Guid PersonId { get; set; } = Guid.NewGuid();
public Guid PetId { get; set; }
}
public class Animal
{
public Guid AnimalId { get; set; } = Guid.NewGuid();
public bool IsMammal { get; set; }
}
...
Animal bootsTheMonkey = new Animal() { IsMammal = true };
Person doraTheExplorer = new Person() { PetId = bootsTheMonkey.AnimalId };
I am trying to write a query which finds "all persons whose pets are mammals".
var query =
from pDoc in PersonDocumentCollection.AsQueryable()
where !pDoc.PetId.Equals(Guid.Empty)
join aDoc in AnimalDocumentCollection.AsQueryable() on pDoc.PetId equals aDoc.AnimalId
where aDoc.IsMammal
select pDoc;
Though this query is incorrect evidenced by the error message
$project or $group does not support {document}.
From searching it looks like this error comes about from the use of where aDoc.IsMammal, more specifically the use of the aDoc within/after the join (Based on this SO question). Though I am not entirely sure if that is the issue.
Overall I am trying to join two IMongoCollections where the first's documents have a field whose value is the BsonId of a document from another collection. Then once joined I would like to first the documents from the first collection on the values of fields in the second.
You could try to do something like this (assuming allPeople is a list of all your Person objects and allAnimals is all your Animal objects):
var query = allPeople
.Join(allAnimals,
p => p.PetId,
a => a.AnimalId,
(p, a) => new { P = p, A = a })
.Where(PA => PA.A.IsMammal == true);
https://dotnetfiddle.net/8lw5ye

Nhibernate and Query example

class Customer
{
public int ID { get; set; }
public string Name { get; set; }
}
class Order
{
public int ID { get; set; }
public string Product { get; set; }
}
var customers = new Customer[]
{
new Customer{ID = 5, Name = "Sam"},
new Customer{ID = 6, Name = "Dave"},
new Customer{ID = 7, Name = "Julia"},
new Customer{ID = 8, Name = "Sue"}
};
var orders = new Order[]
{
new Order{ID = 5, Product = "Book"},
new Order{ID = 6, Product = "Game"},
new Order{ID = 7, Product = "Computer"},
new Order{ID = 8, Product = "Shirt"}
};
IEnumerable<Object> query =
from c in customers
join o in orders on c.ID equals o.ID
select new { c.Name, o.Product };
IList<Object> AA = query.ToList<Object>();
This one return new object that is shown into picture
[But I want to access this object as customer and order how can I get data as 'customerObject.propertyName and order.propertyName" instead of getting array with string. Can I get list of data with two object like customer and order object so I can access those data using that object]
It returns aa[0] = {name=" sam ", product=" Book"} but I want something like aa[0] = {Customer.Name , Order.product }
[1]
You could try to return the mapped objects. Considering you have your mapped entities, try something like this:
var result = (from c in customers
join o in orders on c.ID equals o.ID
select new{ Customer = c, Product = o.Product })
.ToList();
Then you can access you result object as a collection of anonymous objects where you have the Customer property and Product which has your entities.

Getting List of Model1 with List of Model2 in it LINQ - MVC 4 EntityFramework 5

I have a requirement where I need to get a List of Model1 (List) using Linq, the Model1 have List of Model2 (List) in it and I need to fetch that also. For this I have created a Linq but m getting following error:
LINQ to Entities does not recognize the method
'System.Collections.Generic.List1 [OurCourse]
ToList[OurCourse](System.Collections.Generic.IEnumerable1
[OurCourse])' method, and this method cannot be translated into a
store expression.
Please refer below for detail:
I have two tables Colleges and Courses, with following columns:
College: ID, Name, Contact, City, Address
Cource: ID, CollegeID, Name, Years
My project have two view models for them, as follows:
public class OurCollege
{
public string Name { get; set; }
public string Contact { get; set; }
public List<OurCourse> MyCourses { get; set; }
}
public class OurCourse
{
public string Name { get; set; }
public int NumberOfYears { get; set; }
}
Here the the query query which I have prepared but I am getting the error:
var colleges = db.Colleges
.Select(cld => new OurCollege()
{
Name = cld.Name,
Contact = cld.Contact,
MyCourses = cld.Course
.Select(crs => new OurCourse()
{
Name = crs.Name,
NumberOfYears = crs.Years
}).ToList()
}).ToList();
How about doing like this:
MyCourses = from crs in cld.Course
select new OurCourse
{
Name = crs.Name,
NumberOfYears = crs.Years
}
Your complete query will look now:
var colleges = db.Colleges
.Select(cld => new OurCollege()
{
Name = cld.Name,
Contact = cld.Contact,
MyCourses = (from crs in cld.Course
select new OurCourse
{
Name = crs.Name,
NumberOfYears = crs.Years
}).ToList()
}).ToList();
Actually LINQ to Entities converts your query into SQL.It doesn't know how to translate ToList() in SQL
An alternate is to change you List<T> to IEnumerable<T> and remove ToList() frim your original code:
public IEnumerable<OurCourse> MyCourses { get; set; }
and in query:
var colleges = db.Colleges
.Select(cld => new OurCollege()
{
Name = cld.Name,
Contact = cld.Contact,
MyCourses = cld.Course
.Select(crs => new OurCourse()
{
Name = crs.Name,
NumberOfYears = crs.Years
})
}).ToList();
For more details visit this Entity Framework ToList() in nested type (LINQ to Entities does not recognize the method)
A foreach loop will work, you can write the query something like this
var colleges = db.Colleges
.Select(x => new OurCollege()
{
CollegeId = x.CollegeId,
Name = x.Name,
Contact = x.Contact
}).ToList();
foreach (var college in colleges)
{
college.MyCourse = db.Course.Where(x => x.CollegeId == college.CollegeId)
.Select(x => new OurCourse()
{
Name = x.Name,
NumberOfYears = x.Years
}).ToList()
}

Getting the latest entry of each user in LINQ to Entities in a strongly-typed manner

I have a database of users and their check-ins in different places with timestamps, related with a foreign key. A user can check-in any time, and can have arbitrary number of entries. I need a LINQ-to-Entities query that will return the checkins in the database, but return only the latest check-in for each user. I am not really a master of SQL or LINQ grouping, I think I need to group the entries. I've seen LINQ group by and getting latest value. There is an answer (https://stackoverflow.com/a/2657436/811405) that returns what I'm trying to get, but it returns an anonymous class. Is there any way to return the instances of my class in a strongly typed manner without selecting an anonymous class?
UPDATE:
I already have this class:
public partial class LocationUpdate
{
public int ID { get; set; }
public System.DateTime DateUpdated { get; set; }
public System.Data.Entity.Spatial.DbGeography Position { get; set; }
public int UserID { get; set; }
public virtual User User { get; set; }
}
And I have this query:
IQueryable<LocationUpdate> nearbyUserLocations = [some LINQ-to-Entities query];
I want, just below that line, a query like this:
nearbyUserLocations = [collection of each user's latest location update];
I need it still in the type of IQueryable<LocationUpdate>, not some anonymous type.
Yes - if I am reading your question correctly, from your example - instead of doing:
var maxObjects =
from o in myList
group o by o.Name into g
select new { Name = g.Key, Created = g.Max(o => o.Created) };
try doing:
var maxObjects =
from o in myList
group o by o.Name into g
select new MyClass{ Name = g.Key, Created = g.Max(o => o.Created) };
and if you want queryable
maxObjects.AsQueryable<MyClass>();
Assuming that MyClass has public properties Name and Created.
Edit after further information
Here is a testable query...
class Program
{
static void Main(string[] args)
{
List<LocationUpdate> locationUpdates =
new List<LocationUpdate>
{
new LocationUpdate {UserID = 1, Position = 2},
new LocationUpdate {UserID = 1, Position = 3},
new LocationUpdate {UserID = 2, Position = 1},
new LocationUpdate {UserID = 2, Position = 2},
new LocationUpdate {UserID = 1, Position = 4},
new LocationUpdate {UserID = 3, Position = 1}
};
IEnumerable<Tuple<int, List<MyClass>>> result = locationUpdates.GroupBy(x => x.UserID)
.Select(x => new Tuple<int, List<MyClass>>(x.Key,
x.Select(y => new MyClass {Position = y.Position, UserID = y.UserID}).ToList()));
foreach (Tuple<int, List<MyClass>> tuple in result)
{
Console.WriteLine("User {0}", tuple.Item1);
foreach (MyClass myClass in tuple.Item2)
Console.WriteLine("User {0}, Position {1}", myClass.UserID, myClass.Position);
}
Console.ReadLine();
}
public class MyClass
{
public int Position { get; set; }
public int UserID { get; set; }
}
public class LocationUpdate
{
public int Position { get; set; }
public int UserID { get; set; }
}
}
Obviously I have left some of the extra properties off as they were just noise, but you should just be able to add them in the block of code which creates a new MyClass...
You can still make the result queryable - the result contains a grouping which may not be exactly what you were expecting - I think that maybe this result type will fit your needs though, and maybe that's why you couldn't get a suitable Linq query to get you data.
Whether or not it answers your question, I hope this helps!

Categories