Linq to entities navigation properties - c#

In entity framework i have two table (two entities): People and Role with one to many relationship.
In the People tables i have a navigation property to Role:
//People.cs
public virtual ICollection<Role> Role { get; set; }
Now i want retrieve all people that have role as 'barman'. How can i achieve this?
I want use linq to entities in the query expression method. I've tried:
var listPerson = (from p in SiContext.People
where p.Role.Name = 'barman'
select p).ToList();
The problem is that i cannot make p.Ruolo.Name because p.Ruolo is a ICollectionType that doesn't have the property "Name" (while the entity Role has that property)

Since role is a collection, you need to use Any
var listPerson = (from p in SiContext.People
where p.Role.Any(x => x.Name == "barman")
select p).ToList();

Just to complemente your code include ToLower():
var listPerson = (from p in SiContext.People
where p.Role.Any(x => x.Name.ToLower() == "barman")
select p).ToList();

You can try the order way around (assuming you have the reverse navigation property)
var listPerson = SiContext.Role.First(r => r.Name == "barman").People.ToList();

Related

C# LINQ Join multiple tables into one object

Main problem to solve:
How do I get "2 levels down" to get Owner.Pet[n].Toys and put it all in one object right away.
There are three entities in the system: Owner, Pet and Toy.
I am trying to write a query (using LINQ's SQL-like notation) that will bring me single object of class Owner with its inner properties filled = all pets assigned to that owner + each pet having all its toys.
This is what I have so far, it's not working as expected. SQL feelings tell me that I am missing GROUP JOIN somewhere...
var singleOwnerQuery =
from o in owners
join p in pets on o.FirstName = p.OwnerName
join t in toys on p.PetId = t.ToyUniqueId // each toy is unique - there are not "re-usable" toys
where o.Name == "..." && o.LastName == "..."
select new Owner
{
Pets = pets // this should already assign all the toys for each of the pets
};
Any help will be appreciated.
I skipped lot of other properties inside each of the classes to make it simpler
Try the following query. Without model, this is just direction how to do Eager Loading query as in your case.
var singleOwnerQuery =
from o in owners
where o.Name == "..." && o.LastName == "..."
select new Owner
{
Pets = pets.Where(p => o.FirstName == p.OwnerName)
.Select(p => new
{
p.PetId,
Toys = toys.Where(t => p.PetId == t.ToyUniqueId).ToList()
})
.tolist()
};

Get common lists in Linq

I have list of StuedntInfo table
and i have List of Classes
var classesList = GetClasses2nd(2017);
Reasult is
ClassId = 5
ClassId = 4
ClassId = 8
Now is it possible to get list of StudentInfo records dynamically where classes id are present in StudentInfo table?
Also if possible to get list of Location objects as well?
I've had to make a few assumptions about your model / db context, but something like this should work:
var classesList = GetClasses2nd(2017);
//get the class Ids
var classIds = classesList.Select(x => x.ClassId);
var students = db.Students
.Include(x=>x.Location) //assuming you have this navigation property on your model
.Where(x=> classIds.Contains(x.ClassID))
.ToList();
Note: The Include will only work if you have a navigation property set on your model.
https://msdn.microsoft.com/en-us/library/jj574232(v=vs.113).aspx
try Code:
var classidList= ( From p in db.student
group p by p.studentid into jj
select new {
classid=jj.max(c=>c.classid)
}).ToList();

Join tables in NHibernate without mapping

I have the following two objects:
User
class User {
public int role;
}
Role
class Role {
public int id;
public string name;
}
be note that role property inside User is int and not Role, that's our limitations.
I want to join between all the users and each of his role. In the mapping objects there is no reference as you can understand, just a simple type (int).
How do I do that join statement?
It's called a theta join:
var a = (from u in session.Query<User>()
from r in session.Query<Role>()
where u.role == r.id
select new { u.Username, Role = r.name }).ToList();
Assuming you have a Username property on the User class.
Yes, this "theta join" (as I just learned this term) is very handy and let's us not worry about putting in pointless mapping relationships.
WARNING HOWEVER IN USING THIS!!! This tripped me up a lot.
Adding to the above example...
var list = new List<int>( { 2, 3 } ); // pretend in-memory data from something.
var a =
(from u in session.Query<User>()
from x in list
from r in session.Query<Role>()
where u.role == r.id
where r.id == x.id // pretend list wants to limit to only certain roles.
select new { u.Username, Role = r.name }).ToList();
THIS WILL BOMB with some NotSupported exception.
The trick is that anything coming from NHibernate Session must come LAST. So this alteration WILL work:
var a =
(from x in list
from u in session.Query<User>()
from r in session.Query<Role>()
where u.role == r.id
where r.id == x.id // pretend list wants to limit to only certain roles.
select new { u.Username, Role = r.name }).ToList();
And and BTW, you can use join as well, however you have to make sure if you have any nullable data types, that you use the .Value if you are joining to something not-nullable.
var a =
(from x in list
from u in session.Query<User>()
join r in session.Query<Role>() on u.role equals r.id
where r.id == x.id // pretend list wants to limit to only certain roles.
select new { u.Username, Role = r.name }).ToList();
And while we're at it, let's say you have a method that has some dynamic condition. In this example the 'list' which could be a list of roles to filter by, but don't filter at all if the list is not there. Well, if you do the .ToList() then you are causing this query to execute immediately. But instead you can add a condition and then execute it later:
var a =
from u in session.Query<User>()
join r in session.Query<Role>() on u.role equals r.id
where r.id == x.id // pretend list wants to limit to only certain roles.
select new { u.Username, Role = r.name, RoleID = r.id }; // Adding the Role ID into this output.
if (list != null) // assume if the list given is null, that means no filter.
{
a = a.Where(x => list.Contains(x.RoleID));
// WARNING. Unfortunately using the "theta" format here will not work. Not sure why.
}
var b = a.ToList(); // actually execute it.
var c = a.Select(x => new { x.Username, x.Role }).ToList() // if you insist on removing that extra RoleID in the output.
One last thing.. Sometimes some simple logic will fail when executed in the select new { .. } part. I don't have an explanation. In our case the logic was just converting a DB value of a uint to an Enumerator of a model. But to get around that, I just avoided doing that conversion while reading the data but saved the value. Then in a later step, after the data was loaded, I just did the conversion in another LINQ statement.
DISCLAIMER: While I wrote many of these things all the past several weeks, I did not put this code into my compiler to verify 100%.

Get list of child records

I have a database that looks like this:
tbl_Seminar
ID
isActive
tbl_SeminarFees
ID
seminar_id -- foreign key
fee_text
I want to get all seminars that are active (isActive ==1) and a list of the fees associated with that seminar. Each Seminar may have n records in tbl_SeminarFees that are its fees. I am able to return a linq structure that returns me a list of objects that look like this {seminar, SeminarFee} but I wanted to create a nested structure that looks like this:
{seminar, List<SeminarFee>}
What should my linq query look like?
here is my linq currently:
var results = from s in context.Seminar
join p in context.SeminarFees on
s.ID equals p.SeminarID
where s.IsActive == 1
select new
{
Seminar = s,
Fees = p
};
How do I change this to get a list of these: {seminar, List<SeminarFee>}
Thanks
UPDATE
#lazyberezovsky gave me a good idea to use a group join and into another variable. But then how do I loop through the result set. Here is what I have now:
foreach (var seminarAndItsFeesObject in results)
{
//do something with the seminar object
//do something with the list of fees
}
This however gives me the following error:
Argument type 'SeminarFees' does not match the
corresponding member type
'System.Collections.Generic.IEnumerable`1[SeminarFees]'
What am I doing wrong?
Thanks
You can use group join which groups inner sequence items based on keys equality (a.k.a. join..into) to get all fees related to seminar:
var results = from s in context.Seminar
join f in context.SeminarFees on
s.ID equals f.SeminarID into fees // here
where s.IsActive == 1
select new
{
Seminar = s,
Fees = fees
};
You can't call ToList() on server side. But you can map results on client later.
BTW You can define navigation property Fees on Seminar object:
public virtual ICollection<SeminarFee> Fees { get; set; }
In this case you will be able load seminars with fees:
var results = context.Seminar.Include(s => s.Fees) // eager loading
.Where(s => s.IsActive == 1);
var results = from s in context.Seminar
join p in context.SeminarFees on s.ID equals p.SeminarID
where s.IsActive == 1
group p by s into grouped
select new {
Seminar = grouped.Key,
Fees = grouped.ToList()
};

How to solve this join in EF

In the image below I have shown the looks of my tables. For the last couple of hours I am Trying to get the best solution for the Query I need but somehow I am running in circles of EF
I would need a collection of Roles with their Modules. Since there are roles which have no modules assigned it should be a left join. the collection should look like " {role, modules}" Role Should be a single object, and modules should be a collection of "Module" objects.
I tried doing it like this
var x = (from r in _context.Role
from rm in r.RoleModule.DefaultIfEmpty()
join m in _context.Module on rm.ModuleID equals m.ID
select new { role= r, modules=rm }).ToList();
EDIT
As per suggestion by lazyberezovsky I made the partial class
public partial class Role
{
public virtual IEnumerable<Module> Modules { get { return RoleModule.Select(p => p.Module); } }
}
Works fine. Another issue of mine is,.... How can I make the "set" accessor.
Edited
Got this now and it works. But How can I access the collection of modules.
var x = (from r in _context.Role
join rm in _context.RoleModule on r.ID equals rm.RoleID into ps
from rm in ps.DefaultIfEmpty()
select new { role=r, modules=rm.Module }).GroupBy(p => p.role).ToList();
* am using this in wpf to be set as datacontext*
Simplest solution will be defining navigation property for modules in your Role entity:
public class Role
{
// ...
public virtual ICollection<Module> Modules { get; set; }
}
Then you will be able to do eager loading of roles with modules:
var roles = _context.Role.Include(r => r.Modules).ToList();
If your junction table is complex, then create navigation property of ICollection<RoleModule> type which holds both Role and Module. Query will look like:
var query = from r in context.Roles
select new {
Role = r,
Modules = r.RoleModules.Select(rm => rm.Module)
};
Instead of starting from Role, how about starting from the join table instead, if you have navigation properties in that class you can include them.
_context.RoleModule()
.Include("Role")
.Include("Module")
.Select(rm=> new {Role = rm.Role, Module = rm.Module}).ToList();

Categories