dbcontext loading related entities using select(), include() and where() not working

I have the following relationship between the entities. Company 1 ---* Appointments *---1 Employee

I have the .net asp membership in a separate database. Whenever a user is created it can be assigned to companies, employees, or administrators roles.

in the Index action of my Company Controller, I check the logged in user's role. Based on the role, I make different linq query. For example, administrators can get list of all companies, companies can get list of company which has a username property (string) same as the User.Identity.Name. For both of administrators and companies role, it is working fine.

For the employees role, I want to load all the companies that are related to the current employee. I am having hard time to compose a linq query that does this job.

i tried

var companies = db.Companies.Include(c => c.Appointments.Select(a=>a.Employee).Where(e=>e.Username.ToLower() == this.User.Identity.Name.ToLower())).ToList();

to which i get this error "The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties. Parameter name: path"

Here are the source code,

CompanyController

[Authorize]
public class CompanyController : Controller
{
    private MyDBContext db = new MyDBContext();

    //
    // GET: /Company/

    public ViewResult Index()
    {
        var viewModel = new CompanyIndexViewModel();
        if (Roles.IsUserInRole("administrators")) {
            viewModel = new CompanyIndexViewModel { Companies = db.Companies.ToList() };
        }
        else if (Roles.IsUserInRole("companies")) {
            viewModel = new CompanyIndexViewModel { Companies = db.Companies.Where(c => c.Username.ToLower().Equals(this.User.Identity.Name.ToLower())).ToList() };
        }
        else if (Roles.IsUserInRole("employees")) {
            var companies = db.Companies.Include(c => c.Appointments.Select(a=>a.Employee).Where(e=>e.Username.ToLower() == this.User.Identity.Name.ToLower())).ToList();
            viewModel = new CompanyIndexViewModel { Companies = companies.ToList() };
        }

        return View(viewModel);
    }

...

Models

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
namespace TorontoWorkforce.Models
{
    public class Company
    {
        public int CompanyId { get; set; }

        [Required]
        public string Username { get; set; }

        [Display(Name="Company Name")]
        [Required]
        public string Name { get; set; }


        [UIHint("PhoneNumber")]
        public string Phone { get; set; }

        [DataType(DataType.Url)]
        public string Website { get; set; }

        [DataType(DataType.EmailAddress)]
        public string Email { get; set; }

        public AddressInfo AddressInfo { get; set; }

        public virtual ICollection<Contact> Contacts { get; set; }

        public virtual ICollection<Appointment> Appointments { get; set; }

        public Company(){
            this.AddressInfo = new AddressInfo();
        }
    }
}



using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;

namespace TorontoWorkforce.Models
{
    public class Appointment
    {

        public int AppointmentId { get; set; }


        [Required]
        [UIHint("DateTime")]
        [Display(Name="Appointment Date")]
        public DateTime? DateOfAppointment { get; set; }

        [Required]
        public int CompanyId { get; set; }

        [Required]
        public int EmployeeId { get; set; }

        [Required]
        [UIHint("MultilineText")]
        [Display(Name = "Appointment Summary")]
        public string Description { get; set; }

        [Display(Name="Allocated No of Hours")]
        public decimal NoOfHoursWorked { get; set; }

        public virtual Company Company { get; set; }

        public virtual Employee Employee { get; set; }

        public virtual ICollection<AppointmentLine> AppointmentLines { get; set; }

        public Appointment() {
            //this.AppointmentLines = new List<AppointmentLine>();
            this.DateOfAppointment = DateTime.Now;
        }

        [NotMapped]
        [Display(Name="Actual No of Hours")]
        public decimal ActualHoursWorked {
            get
            {
                decimal total = 0;
                foreach (var jobline in this.AppointmentLines)
                {
                    total = total + jobline.TimeSpent;
                }
                return total;
            } 
        }


    }

    public class AppointmentLine
    {
        public int AppointmentLineId { get; set; }

        [UIHint("MultilineText")]
        [Required]
        public string Description { get; set; }

        [Display(Name="Time Spent")]
        [DataType(DataType.Duration)]
        public decimal TimeSpent { get; set; }

        public int AppointmentId { get; set; }

        public virtual Appointment Appointment { get; set; }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;

namespace TorontoWorkforce.Models
{
    public class Employee: TorontoWorkforce.Models.Person
    {
        public int EmployeeId { get; set; }

        [Required]
        public string Username { get; set; }

        [Display(Name="Date Hired")]
        public DateTime? DateHired { get; set; }

        [Required]
        public string Position { get; set; }

        public virtual ICollection<Appointment> Appointments { get; set; }

        public Employee() {
            this.DateHired = DateTime.Now;        
        }
    }
}

Answers


If you want to get companies which have appointment with selected employee you don't need to use Include. Include is for instructing EF to load all appointments related to the company (and it doesn't support filtering). Try this:

string userName = this.User.Identity.Name.ToLower();
var companies = db.Companies.Where(c => c.Appointments.Any(a => 
                   a.Employee.Username.ToLower() == userName)).ToList();

I think you just have an end parentheses in the wrong place. You need one more after "a => a.Employee" and one less after "this.User.Identity.Name.ToLower()));"

Try this code:

var companies = db.Companies.Include(c => c.Appointments.Select(a=>a.Employee)).Where(e=>e.Username.ToLower() == this.User.Identity.Name.ToLower()).ToList();      

Edit: You should also be able to use the standard string include method:

var companies = db.Companies.Include("Appointments.Employee").Where(e=>e.Username.ToLower() == this.User.Identity.Name.ToLower()).ToList();      

Need Your Help

How to get records based on different Id's using rest API?

list api rest sharepoint

I need to get records from a list using REST API based on multiple Id's (Primary Key).

Prefer mobile over WiFi connection

android wifi wlan

My application performs WiFi operations and therefore it needs to stay on the same connection under the whole session.