简体   繁体   中英

Entity Framework Self Referencing Using Non-Primary Key Column

I have an employee table that self references to determine organization structure. I'm having some trouble trying to set this up using Code-First (POCO) fluently.

An employee record has both a "Position" field and a "ReportsTo" field and neither of the columns are the primary key (employee.id).

An employee with a " ReportsTo " value of " 08294 " , is an employee of a direct report of an employee with " Position " value of " 08294 ".

Can anyone offer up some info on how to set this up using EF code first, fluently...is it possible?

I tried the code below and am getting error:

Employee_Employees_Source_Employee_Employees_Target: : The types of all properties in the Dependent Role of a referential constraint must be the same as the corresponding property types in the Principal Role. The type of property 'ReportsTo' on entity 'Employee' does not match the type of property 'Id' on entity 'Employee' in the referential constraint 'Employee_Employees'.

Employee.cs

public class Employee
{
     public int Id  { get; set; } //pk 
     public string Position { get; set; } // i.e. 06895
     public string ReportsTo{ get; set; } // i.e. 08294         

     public virtual Employee Supervisor { get; set; }
     public virtual ICollection<Employee> Employees { get; set; }
}

DbContext

modelBuilder.Entity<Employee>()
                .HasMany(e => e.Employees)
                .WithOptional(e => e.Supervisor)
                .HasForeignKey(e => e.ReportsTo);

I think more than anything, I would like to keep the POCO free of EF "stuff" and be able to do something like:

employee.IsSupervisor(); // based on child employee count. 

The issue is in the relationship configuration. If you want to configure your one to many relation without using a FK, you could do this:

modelBuilder.Entity<Employee>()
            .HasMany(e => e.Employees)
            .WithOptional(e => e.Supervisor);

Now if you want to use a FK property, then add this property to your model class:

public class Employee
{
  //...
  public int SupervisorId  { get; set; }
}

And map your relationship this way:

modelBuilder.Entity<Employee>()
            .HasMany(e => e.Employees)
            .WithOptional(e => e.Supervisor)
            .HasForeignKey(e => e.SupervisorId);

To resolve your issue related with ReportTo and Position properties,I think you should handle that logic in your code. If you want to know if an Employee is a supervisor based on the count of Employees property, you could use a NotMapped property:

 public class Employee
{
  [NotMapped]
  public bool IsSupervisor
  {
     get
     {
         return Employess.Count>0
     }
  }
}

You can do the same using Fluent Api:

modelBuilder.Entity<Employee>().Ignore(e => e.IsSupervisor);

PS: Remember initialize Employees in your class'constructor.

The error you get is because it is trying to map a PK of int type to a FK of string type. User int for all of your key fields.

Then, you need to declare your OnModelBuilding like this:

modelBuilder.Entity<Employee>()
.HasOptional(e => e.Supervisor)
.WithMany()
.HasForeignKey(s => s.ReportsTo);

To get something like IsSupervisor() you can take advantage of partial classes. Create another class file which is a public partial class Employee (and modify your original one to be partial), then in your new file you will add a property that does whatever you want, and decorate it with [NotMapped] attribute. Yours will probably look something like public bool IsSupervisor {get { return (Employees == null) ? false : true; } set {} } public bool IsSupervisor {get { return (Employees == null) ? false : true; } set {} } public bool IsSupervisor {get { return (Employees == null) ? false : true; } set {} } The new partial class is where you can do whatever you want for the POCO without changing the EF class (make sure you use [NotMapped] though).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM