Joe Joe - 1 month ago 16
C# Question

EF Code First One To One Mapping

I have a situation where I have an existing table

Employee
that I am unable to modify due to some short-term compatibility issues with an existing product.

I would like to add a new table
EmployeeOptions
and treat it as a sort of continuation of the employee table.

[Employee]
EmpId | FName | LName

[EmployeeOption]
EmpId | Option1 | Option2


For my actual usage in my application, I would like to be able to use either of the following approaches:

emp.Option1 = "123";


OR

emp.EmployeeOptions.Option1 = "123:


I have looked into Entity Splitting and variations on 1:1 mappings haven't been able to quite get what I am looking for. (The closest I found was here, but the resulting migration added a column to my Employee table)

Is there a recommended way to do this (or a workaround)?

Answer

I think this is it, 1:0..1. An Employee may have an EmployeeOptions, an EmployeeOptions must have an Employee, and Employee table is left untouched by the migration:

public class Employee
{
    [Key]
    public int EmpId { get; set; }

    public string FName { get; set; }

    public string LName { get; set; }

    [ForeignKey("EmpId")]
    public virtual EmployeeOption EmployeeOption { get; set; }
}

public class EmployeeOption
{
    [Key]
    public int EmpId { get; set; }

    public string Option1 { get; set; }

    public string Option2 { get; set; }

    [ForeignKey("EmpId")]
    public virtual Employee Employee { get; set; }
}

public class ExampleContext : DbContext
{
    public ExampleContext() : base("DefaultConnection") { this.Configuration.ProxyCreationEnabled = false; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Employee>()
            .HasOptional(o => o.EmployeeOption)
            .WithOptionalPrincipal(e => e.Employee);
    }

    public DbSet<Employee> Employees { get; set; }
    public DbSet<EmployeeOption> EmployeeOptions { get; set; }
}

Generated tables (migration):

        CreateTable(
            "dbo.EmployeeOptions",
            c => new
                {
                    EmpId = c.Int(nullable: false),
                    Option1 = c.String(),
                    Option2 = c.String(),
                })
            .PrimaryKey(t => t.EmpId)
            .ForeignKey("dbo.Employees", t => t.EmpId)
            .Index(t => t.EmpId);

        CreateTable(
            "dbo.Employees",
            c => new
                {
                    EmpId = c.Int(nullable: false, identity: true),
                    FName = c.String(),
                    LName = c.String(),
                })
            .PrimaryKey(t => t.EmpId);

EDIT: by using the following fluent mapping instead of the one above you can remove both [ForeignKey] attributes:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<EmployeeOption>()
            .HasRequired(e => e.Employee)
            .WithOptional(e => e.EmployeeOption);
    }