EFCore (Fluent Api) 配置1对1,1对多, 多对多配置详解
1. 一对一关系 (One-to-One)
-
HasOne()
: 指定主体实体(Principal)有一个依赖实体(Dependent) -
WithOne()
: 指定依赖实体有一个主体实体 -
HasForeignKey()
: 指定依赖实体中的外键属性
基本配置
// 数据注解方式 public class User { public int Id { get; set; } public string Name { get; set; } public UserProfile Profile { get; set; } // 导航属性 } public class UserProfile { public int Id { get; set; } public string Address { get; set; } public int UserId { get; set; } // 外键 public User User { get; set; } // 导航属性 } // Fluent API 配置 protected override void OnModelCreating(ModelBuilder modelBuilder) { //从主体端配置(从主体端配置和依赖端配置选其一即可) modelBuilder.Entity<User>() .HasOne(u => u.Profile) .WithOne(p => p.User) .HasForeignKey<UserProfile>(p => p.UserId); //从依赖端配置 modelBuilder.Entity<UserProfile>() .HasOne(p => p.User) // Profile有一个User .WithOne(u => u.Profile) // User有一个Profile .HasForeignKey<UserProfile>(p => p.UserId); // 外键在Profile中 }
高级配置选项
modelBuilder.Entity<User>() .HasOne(u => u.Profile) .WithOne(p => p.User) .HasForeignKey<UserProfile>(p => p.UserId) .OnDelete(DeleteBehavior.Cascade) // 级联删除 .IsRequired(); // 是否是必须的 // 共享主键的一对一 modelBuilder.Entity<User>() .HasOne(u => u.Profile) .WithOne(p => p.User) .HasForeignKey<UserProfile>(p => p.Id); // 使用相同主键
2. 一对多关系 (One-to-Many)
基本配置
// 数据注解方式 public class Department { public int Id { get; set; } public string Name { get; set; } public ICollection<Employee> Employees { get; set; } // 导航属性 } public class Employee { public int Id { get; set; } public string Name { get; set; } public int DepartmentId { get; set; } // 外键 public Department Department { get; set; } // 导航属性 } // Fluent API 配置 protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Department>() .HasMany(d => d.Employees) .WithOne(e => e.Department) .HasForeignKey(e => e.DepartmentId); }
高级配置选项
modelBuilder.Entity<Department>() .HasMany(d => d.Employees) .WithOne(e => e.Department) .HasForeignKey(e => e.DepartmentId) .OnDelete(DeleteBehavior.Restrict) // 删除行为 .IsRequired(); // 是否是必须的 // 无导航属性配置 modelBuilder.Entity<Department>() .HasMany<Employee>() // 无导航属性 .WithOne(e => e.Department) .HasForeignKey(e => e.DepartmentId); // 自引用一对多关系(树形结构) modelBuilder.Entity<Employee>() .HasMany(e => e.Subordinates) .WithOne(e => e.Manager) .HasForeignKey(e => e.ManagerId);
3. 多对多关系 (Many-to-Many)
简化配置
// 数据模型 public class Student { public int Id { get; set; } public string Name { get; set; } public ICollection<Course> Courses { get; set; } // 导航属性 } public class Course { public int Id { get; set; } public string Title { get; set; } public ICollection<Student> Students { get; set; } // 导航属性 } // Fluent API 配置(自动连接表) protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Student>() .HasMany(s => s.Courses) .WithMany(c => c.Students); }
自定义连接表配置
// 包含额外属性的连接实体 public class StudentCourse { public int StudentId { get; set; } public Student Student { get; set; } public int CourseId { get; set; } public Course Course { get; set; } public DateTime EnrollmentDate { get; set; } public string Grade { get; set; } } // Fluent API 配置 protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Student>() .HasMany(s => s.Courses) .WithMany(c => c.Students) .UsingEntity<StudentCourse>( j => j.HasOne(sc => sc.Course).WithMany(), j => j.HasOne(sc => sc.Student).WithMany(), j => j.HasKey(sc => new { sc.StudentId, sc.CourseId }) .Property(sc => sc.EnrollmentDate) .HasDefaultValueSql("GETDATE()"); }