EF code first与数据表映射方式有两种实现:1.Data Annotation 和 Fluent API.
1.Data Annotation方式
这种方式就是在字段上面规定字段的属性以及主外键
[Column("ProductID")]
public int ProductID { get; set; }
[MaxLength(100)]
[Required, Column("ProductName")]
public string ProductName { get; set; }
2. Fluent API
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>().Property(t => t.ProductID)
.HasColumnName("ProductID");
modelBuilder.Entity<Product>().Property(t => t.ProductName)
.IsRequired()
.HasColumnName("ProductName")
.HasMaxLength(100);
}
3.主键
Entity Framework Code First的默认主键约束:属性名为[ID]或[类名 + ID]。如在Product类中,Entity Framework Code First会根据默认约定将类中名称为ID或ProductID的属性设置为主键。Entity Framework Code First主键的默认约定也一样可以进行重写,重新根据需要进行设置。
[Key]
[Column("ProductID")]
public int ProductID { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>().HasKey(t => t.ProductID);
}
4.关系映射
EF里的实体关系配置分为Has和With系列的方法:Optional 可选的、Required 必须的、Many 多个。举例:
A.HasRequired(a => a.B).WithOptional(b => b.A);
这里的a=>a.B是lambda表示写法,就是找到A类里的导航属性B。命名a不固定,可以随意,q=>q.B也是可以的。但是B是A类的属性,故习惯用小写a。
Has方法:
- HasOptional:前者包含后者一个实例或者为null
- HasRequired:前者(A)包含后者(B)一个不为null的实例
- HasMany:前者包含后者实例的集合
With方法:
- WithOptional:后者(B)可以包含前者(A)一个实例或者null
- WithRequired:后者包含前者一个不为null的实例
- WithMany:后者包含前者实例的集合
4.1 一对一
一对一关系两端具有引用导航属性。 它们遵循相同的约定作为一个对多关系,但在外键属性,以确保只有一个依赖于与每个主体上引入了唯一索引。
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public BlogImage BlogImage { get; set; }
}
public class BlogImage
{
public int BlogImageId { get; set; }
public byte[] Image { get; set; }
public string Caption { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
备注
EF 将选择一个要为基于它能够检测到外键属性的依赖项的实体。 如果错误的实体选择作为依赖项,可以使用 Fluent API 要更正此问题。
如果使用 Fluent API 配置此关系,则使用HasOne
和WithOne
方法。
配置需要指定依赖实体类型中的外键时请注意,泛型参数提供给HasForeignKey
下面的列表中。 一个对多关系中很明显,引用导航的实体与相关和具有集合是的主体。 但这并不是一对一关系-因此中显式定义的需要。
class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<BlogImage> BlogImages { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasOne(p => p.BlogImage)
.WithOne(i => i.Blog)
.HasForeignKey<BlogImage>(b => b.BlogForeignKey);
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public BlogImage BlogImage { get; set; }
}
public class BlogImage
{
public int BlogImageId { get; set; }
public byte[] Image { get; set; }
public string Caption { get; set; }
public int BlogForeignKey { get; set; }
public Blog Blog { get; set; }
}
4.2 一对多
一对多与一对一不同,一对多不需要显示指定主外键,显然,code first会自己判断,blog含有集合属性的post,post里面会自动加上blogId作为外键。
class MyContext : DbContext
{
public DbSet<Post> Posts { get; set; }
public DbSet<Blog> Blogs { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
}
public class Blog
{
public int BlogId { get; set; }
public string BlogName { get; set; }
public List<Post> Posts { get; set; }
}
4.3 多对多
尚不支持多对多关系,而不需要的实体类来表示联接表。 但是,您可以通过包括联接表和映射两个单独一个对多关系的实体类表示多对多关系。
class MyContext : DbContext
{
public DbSet<Post> Posts { get; set; }
public DbSet<Tag> Tags { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<PostTag>()
.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);
}
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public List<PostTag> PostTags { get; set; }
}
public class Tag
{
public string TagId { 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; }
}