Search code examples
c#entity-frameworkentity-framework-6

EF multiple foreign key relationship on same primary key ApplicationUser table


I want to create a one-to-many relationship using EF 6 using a code-first approach.

Let's take simple and classical example. I have two entities Invoice and UserApplication which have a one-to-many relationship:

I also want to have an UpdatedById relationship with the same ApplicationUser table, to be able to show the names in the UI of who added the record and who modified it.

 public partial class ApplicationUser : IdentityUser
    {
     public string FirstName { get; set; };
     public string  LastName { get; set; };
    }
     public virtual List<Invoice> Invoices { get; set; }
    
    
    
    public class Invoice
    {
     public int Id { get; set; }
     public string Details { get; set; }
     public string CreatedById { get; set; }
     public string UpdatedById { get; set; }
    }
     public virtual ApplicationUser CreatedBy { get; set; }
    
     builder.Entity<Invoice>()
     .HasOne(f => f.CreatedBy)
     .WithMany(mu => mu.Invoices)
     .HasForeignKey(f => f.CreatedById);

Solution

  • If you want Navigation Properties on Application user for these relationships, you would need to create and configure seperate ones.

    eg

    using Microsoft.EntityFrameworkCore;
    using System.Linq;
    using System;
    using System.Collections.Generic;
    
    namespace EfCore6Test
    {
    
        public partial class ApplicationUser //: IdentityUser
        {
            public int Id { get; set; }
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public virtual ICollection<Invoice> InvoicesCreated { get; } = new HashSet<Invoice>();
            public virtual ICollection<Invoice> InvoicesLastUpdated { get; } = new HashSet<Invoice>();
        }
        
        public class Invoice
        {
            public int Id { get; set; }
            public string Details { get; set; }
            public int CreatedById { get; set; }
            public int UpdatedById { get; set; }
            public virtual ApplicationUser CreatedBy { get; set; }
            public virtual ApplicationUser LastUpdatdBy { get; set; }
        }
        
        public class Db: DbContext
        {
            public DbSet<Invoice> Invoices{ get; set; }
            public DbSet<ApplicationUser> Users{ get; set; }
    
            protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                modelBuilder.Entity<Invoice>()
                            .HasOne(f => f.CreatedBy)
                            .WithMany(mu => mu.InvoicesCreated)
                            .HasForeignKey(f => f.CreatedById)
                            .OnDelete(DeleteBehavior.Restrict); 
    
                modelBuilder.Entity<Invoice>()
                            .HasOne(f => f.LastUpdatdBy)
                            .WithMany(mu => mu.InvoicesLastUpdated)
                            .HasForeignKey(f => f.UpdatedById)
                            .OnDelete(DeleteBehavior.Restrict);
    
                base.OnModelCreating(modelBuilder);
            }
            protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            {
                optionsBuilder.UseSqlServer("Server=localhost;database=efCore6Test;Integrated Security=true;TrustServerCertificate=true", o => o.UseRelationalNulls(true))
                    .LogTo(Console.WriteLine, Microsoft.Extensions.Logging.LogLevel.Information);
                base.OnConfiguring(optionsBuilder);
            }
        }
        class Program
        {
            static void Main(string[] args)
            {
                {
                    
                    using var db = new Db();
                    db.Database.EnsureDeleted();
                    db.Database.EnsureCreated();
                   
    
                }
    
    
            }
        }
    }
    

    Or simply omit the Navigation Properties on Application User.