MVC 4 explicitly load a many to many EF lookup and filter by both keys - asp.net-mvc

I have the following in an MVC4 app. I want to filter the load by both keys, there could be many to many but both the keys together represent a unique row. The goal to to explicitly load these collections only when needed and filter by both sides of the relationship.
I have the following Entity.DBContext, it works but only for the UserId key.
context.UserProfiles.Include(o => o.CoachOfOrginizations).Where(p => p.UserId == UserId).Single()
Also this loads all of them, but of course doesnt filter at all, just showing you so you know that I set up my fluent code properly.
context.Entry(this).Collection(t => t.AdministratorOfOrginizations).Load();
modelBuilder.Entity<UserProfile>()
.HasMany(p => p.CoachOfOrginizations)
.WithMany(t => t.Coaches)
.Map(mc =>
{
mc.ToTable("OrganizationCoaches");
mc.MapLeftKey("UserProfileID");
mc.MapRightKey("OrganizationID");
});
CoachOfOrginizations is the following property on UserProfile.
public ICollection<Organization> CoachOfOrginizations { get; set; }
What i would like is to filter my original .Include above based on Organization.ID (the other key) and the currently used key p.UserId. I've tried the following and it doesn't work, any advice? "this" is the UserProfile object.
context.Entry(this)
.Collection(b => b.CoachOfOrginizations)
.Query()
.Where(p => p.ID == orgID)
.Load();

You can do both filtering in a single query. See conditional includes.
var query = context.UserProfiles
.Where(p => p.UserId == UserId)
.Select(p => new { p, Orgs = p.CoachOfOrginizations.Where(o => o.ID == orgID) });
var profiles = query.AsEnumerable().Select(a => a.p);

Related

EF 6 query get a single entry from other table

I am new to EF 6, then I stumble upon this query and I need to modify it to include the data from OrderDelay table. I only intend to get a single row from the database so I tried
.Include(m => m.OrderDelay.FirstOrDefault()) instead of .Include(m => m.OrderDelay). But it does not work. Any idea on how to get just a single row for this table?
var res = await _db
.Include(m => m.BusAdd)
.ThenInclude(b => b.Suburb)
.ThenInclude(s => s.State)
........
.Include(m => m.OrderDelay)
.AsNoTracking()
.SingleOrDefaultAsync(p => p.Id == id);
return res;
it does return a single row from sql the main _db.SingleOrDefaultAsync(p => p.Id == id);
if you use Include() sql-c# translation of outer join it will satisfy the main condition of the Where() and return everything that the included table is linked to.
so it will return
1 main row that satisfy the main condition of SingleOrDefaultAsync(p => p.Id == id);
multiple foreign table row
If you are pertaining to only one result _db then do not use/add multiple Include(x => x.TableName)
Just use _db.SingleOrDefaultAsync(p => p.Id == id);
But if you want to have all the Joined tables but only one of each BusAdd, Suburb, State, OrderDelay
then insert .Select() before/after SingleOrDefaultAsync() with conditions of
{
prop1 = row.prop1,
prop2 = row.prop2,
BusAdds = row.BusAdds.FirstOrDefault/SingleOrDefaultAsync(add condition here or none),
Suburbs = row.Suburbs.FirstOrDefault/SingleOrDefaultAsync(add condition here or none),
States = row.States.FirstOrDefault/SingleOrDefaultAsync(add condition here),
OrderDelay = row.OrderDelay.FirstOrDefault/SingleOrDefault(add condition here or none)
}

how to apply inner join in entityframework LINQ method syntax?

How to apply this query in entity framework method syntax
select company_id, country_id from companies, departments where companies.company_id == departments.company_id and department.departmentId = 10;
So far, I have:
var company = context.companies
.Where(com => com.Departments
.Contains(context.departments
.Where(dep => dep.department_id==_user.Department)
.FirstOrDefault()
)
)
.Select(com => new { com.company_id, com.Country })
.FirstOrDefault();
Using method based syntax, this could be as simple as;
var company = context.Companies
.Where(x => x.Departments
.Any(x => x.department_id == _user.Department)
)
.Select(x => new { x.company_id, x.Country });
This assumes your tables are set up with foreign keys giving each Company a list of Department objects. It very much depends on your data structure.

Pass a result of multiple grouping to View

Db.Deliveries.Where(d => d.CrewId != null).GroupBy(d => new {d.Crew, d.Date}).OrderBy(d => d.Key).ToList()
How to pass the result of this code to View? Code is valid. What type must have View?
var Deliveries = Db.Deliveries.Where(d => d.CrewId != null).GroupBy(d => new {d.Crew, d.Date}).OrderBy(d => d.Key).ToList(); //It`s Ok.
List<IGrouping<{Crew:Crew, Date:DateTime}, Delivery>> Deliveries = Db.Deliveries.Where(d => d.CrewId != null).GroupBy(d => new {d.Crew, d.Date}).OrderBy(d => d.Key).ToList(); //It`s wrong.
List<IGrouping<{Crew, DateTime}, Delivery>> //This type is wrong too.
Or is exists any solution of this problem, without using anonymious types?
Sorry for my bad English, Thanks for any help!
Because you use an anonymous type in your GroupBy the result the type exists only virtually.
Either use
#model dynamic
or define a type for your result
public class GroupedDelivery{
public Crew Crew {get;set;}
public DateTime Date {get;set;}
public List<Delivery> Deliveries {get;set;}
}
Map the type in a Select after the GroupBy.
List<GroupedDelivery> Deliveries = Db.Deliveries.Where(d => d.CrewId != null)
.GroupBy(d => new {d.Crew, d.Date})
.Select(p => new GroupedDelivery{
Crew = p.Key.Crew,
Date = p.Key.Date,
Deliveries = p.Select(x => x).ToList()
})
.OrderBy(d => d.Crew).ThenBy(p => p.Date).ToList();

Selecting nested navigation properties will generate the same SQL statement when selecting separate navigation properties

I have the following repository method:-
public AccountDefinition GetCustomer2(int id)
{ var c = entities.AccountDefinitions.Where(p => p.ORG_ID == id)
.Include(a => a.SDOrganization)
.Include(a2 => a2.SiteDefinitions)
.Include(a3 => a3.SDOrganization.AaaPostalAddresses)
.Include(a4 => a4.SiteDefinitions.Select(a5 => a5.DepartmentDefinitions.Select(a6 => a6.SDUsers.Select(a7 => a7.AaaUser.AaaContactInfoes)))).SingleOrDefault();
return c; }
But when I comment some code I found that the generated SQL statement when calling the Action method will be the same:-
public AccountDefinition GetCustomer2(int id)
{ var c = entities.AccountDefinitions.Where(p => p.ORG_ID == id)
// .Include(a => a.SDOrganization)
// .Include(a2 => a2.SiteDefinitions)
.Include(a3 => a3.SDOrganization.AaaPostalAddresses)
.Include(a4 => a4.SiteDefinitions.Select(a5 => a5.DepartmentDefinitions.Select(a6 => a6.SDUsers.Select(a7 => a7.AaaUser.AaaContactInfoes)))).SingleOrDefault();
return c; }
So does this mean when I navigate to a nested Navigation property , then EF will automatically retrieve parent navigation properties also? . so for example when i write .Include(a3 => a3.SDOrganization.AaaPostalAddresses) , then there is no need to write .Include(a => a.SDOrganization)
In a nutshell yes, it has to otherwise there is no way for you to traverse to that navigation property
EG, the only way to access AccountDefinition.SDOrganization.AaaPostalAddresses is if SDOrganization is not null.
Having said that my personal preference is to make this intermediate inclusion explicit by listing it anyway. While this has no functional benefit its a reminder that this property will also be returned

Querying Many to Many and Conditional Where

Within my Context file, I set up a many to many relationship between my Location class and Program class.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Location>()
.HasMany(u => u.Programs)
.WithMany(r => r.Locations)
.Map(m =>
{
m.ToTable("LocationsPrograms");
m.MapLeftKey("LocationId");
m.MapRightKey("ProgramId");
});
}
I'm creating a search/filter form where the user will need to be able to filter the locations by selecting a program.
My thought was to query the junction (M2M) table and then join that back up with the locations table.
The problem is that I don't have a class representing the M2M table other than in my OnModelCreating method.
Can I get an example on how to do this?
Basically select * from locations l join locationsprograms lp on l.LocationId = lp.locationid and lp.programid = whatever was passed in.
Thank you.
var locations = dbContext.Locations
.Where(l => l.Programs.Any(p => p.ProgramId == whateverWasPassedInId))
.ToList();
Or (works because your are filtering by the primary key property of Program):
var locations = dbContext.Programs
.Where(p => p.ProgramId == whateverWasPassedInId)
.Select(p => p.Locations)
.SingleOrDefault();

Resources