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()");
}

 

posted @ 2025-07-30 16:50  龙卷风吹毁停车场  阅读(47)  评论(0)    收藏  举报