How do I set up the relation using Fluent API between an Employee entity and an ICollection<Employee>?

96 views Asked by At

I am using entity framework and I have an Employee entity among other entities. One navigation property that I want Employee to have is a list of Employees that this Employee manages. This is the Employee class (it actually uses an EF prefix, but I'm referring to it without the prefix to make it less confusing):

/// <summary>
/// The Class model for the Employee Entity
/// </summary>
[Table("employee_entity")]
public class EFEmployee : EFBusinessEntity
{
    /// <summary>
    /// The hire date of the employee
    /// </summary>
    [Column("hire_date")]
    public DateTime HireDate { get; set; }

    /// <summary>
    /// The list of jobtitles for the employee
    /// </summary>
    [Column("job_title")]
    [Required]
    public byte[] JobTitle { get; set; }

    /// <summary>
    /// The Employee's salary (note: not attached to jobtitle necessarily)
    /// </summary>
    [Column("salary")]
    public int Salary { get; set; }

    /// <summary>
    /// List of Certifications for the employee
    /// </summary>
    [Column("certifications")]
    public byte[] Certifications { get; set; }

    /// <summary>
    /// Employee's stored up vacation time
    /// </summary>
    [Column("vacation_time")]
    public int VacationTime { get; set; }

    /// <summary>
    /// Employee's stored up sick time
    /// </summary>
    [Column("sick_time")]
    public int SickTime { get; set; }

    /// <summary>
    /// Maps the employee entity to the office entity
    /// </summary>
    [ForeignKey("office_entity")]
    public virtual EFOffice Office { get; set; }

    /// <summary>
    /// Maps the employee entity to the person entity
    /// </summary>
    public virtual EFPerson Identity { get; set; }

    /// <summary>
    /// Maps the employee entity to another employee entity
    /// </summary>
    public virtual EFEmployee ReportingTo { get; set; }

    /// <summary>
    /// Maps the employee entity to a collection of employee entites
    /// </summary>
    public virtual ICollection<EFEmployee> Managing { get; set; }

    /// <summary>
    /// Constructor for an Entity. Only requires the properties that cannot be null.
    /// </summary>
    /// <param name="Id"></param>
    /// <param name="TenantId"></param>
    /// <param name="hire"></param>
    /// <param name="titles"></param>
    /// <param name="salary"></param>
    /// <param name="certifications"></param>
    /// <param name="vacationTime"></param>
    /// <param name="sickTime"></param>
    public EFEmployee(Guid Id, Guid TenantId, DateTime hire, byte[] titles, int salary, byte[] certifications, int vacationTime, int sickTime)
    {
        this.HireDate = hire;
        this.JobTitle = titles;
        this.Salary = salary;
        this.Certifications = certifications;
        this.SickTime = sickTime;
        this.VacationTime = vacationTime;
    }
}

As you can see, one of Employee's navigation properties is

public virtual ICollection<EFEmployee> Managing { get; set; }

I have a an EmployeeMap class that uses Fluent API to establish the relationships between the Employee entity and other entities. It's incomplete right now, but this is what it looks like:

public partial class EmployeeMap : EntityTypeConfiguration<EFEmployee>
{
    public EmployeeMap()
    {
        // Relations
        HasRequired(t => t.Office).WithMany(u => u.Employees);
        HasMany(t => t.Managing).WithRequired(u => u.Employees);
    }
}

The first relation with the office and employees works and makes sense, since there are many Employee entities for each Office entity. However, I'm getting an error for the second relation mapping. Specifically, the 'Employees' at the end gives an error saying

Employee does not contain a definition for 'Employees' and no extension method etc...

It's pretty obvious why I get that error. I haven't declared a property in Employee for Employees and I don't know why I would. But then how do I set up relationships between two entities of the same type? If you look back at my Employee entity class, I also have the navigation property:

public virtual EFEmployee ReportingTo { get; set; }

Here I'm also trying to set up a relation between an Employee and another Employee, but I don't know how that would work since in an entity data model the Employee entity is just represented as one table with its properties. Does anyone know what I'm talking about and how to get around it?

1

There are 1 answers

1
jjj On BEST ANSWER

When you're defining relationships, the properties you use need to be the inverse of each other. In the case of Managing, I think what you're looking for is:

HasMany(t => t.Managing).WithRequired(t => t.ReportingTo);

Because I'm guessing you want:

someEmployee.ReportingTo.Managing.Contains(someEmployee) == true

and you want each EFEmployee in someManager.Managing to have ReportingTo == someManager.


If you don't actually have an inverse property defined, you don't need to have one in the model configuration:

// someEmployee can possibly have many other EFEmployees with 
// ReportingTo == someEmployee, but no collection property on someEmployee to 
// represent that relationship!
HasRequired(t => t.ReportingTo).WithMany();