外键
什么是外键 百度百科
EF教程
EF教程
EF6(关系)微软官方文档
EF Core(关系)微软官方文档
EF外键约定
外键定义在从表中;
从表外键名字段一般默认为: "主表实体名称+Id";
如果不指定主表字段,从表外键值默认等于主表的值;
建议看官方文档,里面真的很详细.
以下是个人见解
表关联时都会区分主表和从表,主表和从表都有自己的主键(primary key);
主表:不一定会强关联从表,毕竟如人员信息表,很多业务表都用到,不可能在人员信息表里逐一关联;
从表:跟主表一定是强关联的,一定是依赖主表的某一个或多个字段为自身对应的键,也就是外键(foreign key);
一对一
有两个类,User是主表,UserExpand是从表,如下
public class User
{
public int Id{ get; set; }
public string Name { get; set; }
}
public class UserExpand{
public int Id{get;set;}
public int Age{get;set;}
}
特性标注
public class User
{
public int Id{ get; set; }
public string Name { get; set; }
public UserExpand UserExpand { get; set; } //看情况而加,加的话可以方便EF Include联查
}
public class UserExpand{
public int Id{get;set;}
public int Age{get;set;}
public int UserId{get;set;}
[ForeignKey(nameof(UserId))]
public User User{get;set;}
}
或者
public class UserExpand{
public int Id{get;set;}
public int Age{get;set;}
[ForeignKey(nameof(User))]
public int UserId{get;set;}
public User User{get;set;}
}
Fluent API配置
EF6 默认自动关联,不需要配置;
EF Core
public void Configure(EntityTypeBuilder<UserExpand> builder)
{
builder.HasKey(e => e.Id);//配置UserExpand 的主键
builder.HasOne<User>(e=>e.User) //UserExpand有一个(HasOne)User类型的关联,属性是e.User
//这个关联类型User(WithOne)跟自己(UserExpand)的关联关系是"有一个"
.WithOne() //或者 WithOne(e=>e.UserExpand) 如果User 带有UserExpand的时候
.HasForeignKey(e => e.UserId); //指定与User 关联的外键
}
一对多
有两个类,Main是主表,Detailed是从表,如下
Detailed也是Main的明细表
public class Main
{
public Guid Id{ get; set; }
public string Name { get; set; }
}
public class Detailed{
public int Id{get;set;}
public Guid MainId{get;set;}
public byte[] Data{get;set;}
}
特性标注
public class Main
{
public Guid Id{ get; set; }
public string Name { get; set; }
public virtual ICollection<Detailed> Detaileds{ get; set; }
}
public class Detailed{
public int Id{get;set;}
// [ForeignKey(nameof(Main))] //也可以这样
public Guid MainId{get;set;}
public byte[] Data{get;set;}
[ForeignKey(nameof(MainId))]
public virtual Main Main{ get; set; }
}
Fluent API配置
EF6
//在Detailed表配置
public class DetailedConfig:EntityTypeConfiguration<Detailed>{
public DetailedConfig(){
HasKey(e => e.Id);
HasRequired<Main>(e=>e.Main) //Detailed有一个Main类型的Main属性
.WithMany(e=>e.Detaileds) //在Main类型身上有(WithMany)许多个对应的ICollection<Detailed>,属性是Detaileds
.HasForeignKey(e=>e.MainId); //指定Detailed对Main的外键是MainId,对应着Main的主键Id
}
}
EF Core
//与EF6类似的
public void Configure(EntityTypeBuilder<Detailed> builder)
{
builder.HasKey(e => e.Id);
builder.HasOne<Main>(e=>e.Main)
.WithMany(e=>e.Detaileds)
.HasForeignKey(e => e.MainId);
}
//也可以在主表配置
public void Configure(EntityTypeBuilder<Main> builder)
{
builder.HasKey(e => e.Id);
builder.HasMany<Detailed>(e=>e.Detaileds)
.WithOne(e=>e.Main)
.HasPrincipalKey(e => e.Id);
}
多对多
多对多比较特殊点的就是需要依靠中间表
举例如下:Post,Tag,PostTag三个实体
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public ICollection<Tag> Tags { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class Tag
{
public string TagId { get; set; }
public ICollection<Post> Posts { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class PostTag
{
public int PostId { get; set; }
public Post Post { get; set; }
public string TagId { get; set; }
public Tag Tag { get; set; }
}
Fluent API配置
EF6 配置
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>()
.HasMany(t => t.Tags)
.WithMany(t => t.Posts)
.Map(m =>
{
m.ToTable("PostTag");
m.MapLeftKey("TagId");
m.MapRightKey("PostId");
});
}
EF Core配置
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//直接多对多配置
modelBuilder.Entity<Post>()
.HasMany(p => p.Tags)
.WithMany(p => p.Posts)
.UsingEntity<PostTag>(
j => j
.HasOne(pt => pt.Tag)
.WithMany(t => t.PostTags)
.HasForeignKey(pt => pt.TagId),
j => j
.HasOne(pt => pt.Post)
.WithMany(p => p.PostTags)
.HasForeignKey(pt => pt.PostId),
j =>
{
j.HasKey(t => new { t.PostId, t.TagId });
});
//间接多对多配置
modelBuilder.Entity<PostTag>()
.HasOne(pt => pt.Post)
.WithMany(p => p.PostTags)
.HasForeignKey(pt => pt.PostId);
modelBuilder.Entity<PostTag>()
.HasOne(pt => pt.Tag)
.WithMany(t => t.PostTags)
.HasForeignKey(pt => pt.TagId);
}