EF Core的入门使用总结

一、初步使用

  1. 依赖注入设置
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    services.AddDbContext(
        options => options.UseSqlServer("name=ConnectionStrings:DefaultConnection"));
}
  1. 创建DbContext
public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions options)
        : base(options)
    {
    }
}
  1. 关于构造函数 —— EF不关心private/public 它都可以调用
  • EF会调用默认无参构造函数,然后把对应的属性值显式设置为数据库中的值
  • 但如果EF 查找到参数名称(首字母大小写不敏感)和类型都匹配,将调用该构造函数,对于其他的一些属性,它将通过正常显式设置
  • 只读属性是不会被设置的 —— 不会按约定映射没有 setter 的属性。 (这样做通常是为了映射不应映射的属性,如计算属性。 )
public class Blog
{
    public Blog(int id, string name, string author)
    {
        Id = id;
        Name = name;
        Author = author;
    }

    public int Id { get; set; }

    public string Name { get; set; }
    public string Author { get; set; }

    public ICollection Posts { get; } = new List();
}

public class Post
{
    public Post(int id, string title, DateTime postedOn)
    {
        Id = id;
        Title = title;
        PostedOn = postedOn;
    }

    public int Id { get; set; }

    public string Title { get; set; }
    public string Content { get; set; }
    public DateTime PostedOn { get; set; }

    public Blog Blog { get; set; }
}

二、Fluent Api使用

  1. 模型配置
internal class MyContext : DbContext
{
    public DbSet Blogs { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity();
    }
}
  1. 忽略某个类型
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Ignore();
}
  1. 忽略/排除属性
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity()
        .Ignore(b => b.LoadedFromDatabase);
}
  1. 指定表名
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity()
        .ToTable("blogs");
}
  1. 配置列名
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity()
        .Property(b => b.BlogId)
        .HasColumnName("blog_id");
}
  1. 配置列的数据类型
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity(
        eb =>
        {
            eb.Property(b => b.Url).HasColumnType("varchar(200)");
            eb.Property(b => b.Rating).HasColumnType("decimal(5, 2)");
        });
}
  1. 配置最大长度
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity()
        .Property(b => b.Url)
        .HasMaxLength(500);
}
  1. 显示配置必须的
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity()
        .Property(b => b.Url)
        .IsRequired();
}
  1. 排序规则
modelBuilder.Entity().Property(c => c.Name)
    .UseCollation("SQL_Latin1_General_CP1_CI_AS");
  1. 配置主键
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity()
        .HasKey(c => c.LicensePlate);
}
//配置主键约束名称
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity()
        .HasKey(b => b.BlogId)
        .HasName("PrimaryKey_BlogId");
}

三、Fluent Api 生成默认值

// 固定值
 protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity()
        .Property(b => b.Rating)
        .HasDefaultValue(3);
}
// 当前日期
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity()
        .Property(b => b.Created)
        .HasDefaultValueSql("getdate()");
}

四、实体之间的关系

HasOne/HasMany 用以标识实体的导航属性
WithOne/WithMany 用以标识实体的反向导航属性

  1. 单个导航属性
internal class MyContext : DbContext
{
    public DbSet Blogs { get; set; }
    public DbSet Posts { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity()
            .HasOne(b => b.Post)
    }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public Post Post { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
}
  1. 配置外键
internal class MyContext : DbContext
{
    public DbSet Blogs { get; set; }
    public DbSet Posts { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity()
            .HasOne(p => p.Blog)
            .WithMany(b => b.Posts)
            .HasForeignKey(p => p.BlogForeignKey);
    }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public List Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogForeignKey { get; set; }
    public Blog Blog { get; set; }
}
  1. 级联删除
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity()
        .HasOne(p => p.Blog)
        .WithMany(b => b.Posts)
        .OnDelete(DeleteBehavior.Cascade);
}
  1. 1对1关系

 protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity()
            .HasOne(p => p.BlogImage )
            .WithOne(b => b.Blog);
    }

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; }
}
  1. 多对多 - 该关系是通过一个额外的联接表来表示的
internal class MyContext : DbContext
{
    public MyContext(DbContextOptions options)
        : base(options)
    {
    }

    public DbSet Posts { get; set; }
    public DbSet Tags { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity()
            .HasMany(p => p.Tags)
            .WithMany(p => p.Posts)
            .UsingEntity(
                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.Property(pt => pt.PublicationDate).HasDefaultValueSql("CURRENT_TIMESTAMP");
                    j.HasKey(t => new { t.PostId, t.TagId });
                });
    }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public ICollection Tags { get; set; }
    public List PostTags { get; set; }
}

public class Tag
{
    public string TagId { get; set; }

    public ICollection Posts { get; set; }
    public List PostTags { get; set; }
}

public class PostTag
{
    public DateTime PublicationDate { get; set; }

    public int PostId { get; set; }
    public Post Post { get; set; }

    public string TagId { get; set; }
    public Tag Tag { get; set; }
}
CREATE TABLE [Posts] (
    [PostId] int NOT NULL IDENTITY,
    [Title] nvarchar(max) NULL,
    [Content] nvarchar(max) NULL,
    CONSTRAINT [PK_Posts] PRIMARY KEY ([PostId])
);

CREATE TABLE [Tags] (
    [TagId] nvarchar(450) NOT NULL,
    CONSTRAINT [PK_Tags] PRIMARY KEY ([TagId])
);

CREATE TABLE [PostTag] (
    [PostsId] int NOT NULL,
    [TagsId] nvarchar(450) NOT NULL,
    CONSTRAINT [PK_PostTag] PRIMARY KEY ([PostsId], [TagsId]),
    CONSTRAINT [FK_PostTag_Posts_PostsId] FOREIGN KEY ([PostsId]) REFERENCES [Posts] ([PostId]) ON DELETE CASCADE,
    CONSTRAINT [FK_PostTag_Tags_TagsId] FOREIGN KEY ([TagsId]) REFERENCES [Tags] ([TagId]) ON DELETE CASCADE
);

五、索引

  1. 简单索引
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity()
        .HasIndex(b => b.Url);
}
  1. 复合索引
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity()
        .HasIndex(p => new { p.FirstName, p.LastName });
}
  1. 唯一索引
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity()
        .HasIndex(b => b.Url)
        .IsUnique();
}

六、值类型转换

  1. 把某个字段存为字符串,借而取的时候转换为对象
modelBuilder.Entity()
                        .Property(e => e.UrlConfig)
                        .HasConversion(v => JsonConvert.SerializeObject(v), 
                                       s => JsonConvert.DeserializeObject(s));
  1. 内置转换器
protected override void OnModelCreating(ModelBuilder modelBuilder)
{ 
    //把一个int类型转为bool类型
    modelBuilder
        .Entity()
        .Property(e => e.IsActive)
        .HasConversion();
}
  1. 定义一个Converter
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    var converter = new ValueConverter(
        v => v.ToString(),
        v => (EquineBeast)Enum.Parse(typeof(EquineBeast), v));

    modelBuilder
        .Entity()
        .Property(e => e.Mount)
        .HasConversion(converter);
}

七、继承 映射生成Table

  • 对于如下的继承关系类
public class Resort : Lodging  //这里继承了Lodging类
   {
       public string Entertainment { get; set; }  //娱乐
       public string Activities { get; set; }  //活动
   }
  1. TPH(Table Per Hierarchy) —— 建立一个大表,所有列都在该表里面,有一个列标识是来着什么类的。

这是EF的默认的继承映射关系:一张表存放基类和子类的所有列,自动生成的discriminator列用来区分基类和子类的数据

如上,实际会生成:


image.png

这种就是把所有的字段都生成到了一张表里面

  1. TPT (Table Per Type) —— 每个之类都生成一个表,但是只包含之类自己的列(不含基类的列)
  • 比如这个例子会生成两个表,通过LodgingId来匹配


    image.png
  1. TPC(Table Per Concrete Type)—— 每个之类都建一个表。子类的表的列会包含它继承的父类的所有字段
  • 当前例子下,会生成如下的表
    image.png

    官网结构介绍文档

八、性能诊断

  1. 简单日志记录
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder
        .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Blogging;Integrated Security=True")
        .LogTo(Console.WriteLine, LogLevel.Information);
}

输出大概如下:

info: 06/12/2020 09:12:36.117 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (4ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT [b].[Id], [b].[Name]
      FROM [Blogs] AS [b]
      WHERE [b].[Name] = N'foo'
  1. 基准测试 —— benchmarkdotnet
方法 平均值 错误 标准偏差 中值 比率 RatioSD 第0代 第1代 第2代 已分配
LoadEntities 2860.4 54.31 93.68 2844.5 4.55 0.33 210.9375 70.3125 - 1309.56 KB
LoadEntitiesNoTracking 1353.0 21.26 18.85 1355.6 2.10 0.14 87.8906 3.9063 - 540.09 KB
ProjectOnlyRanking 910.9 20.91 61.65 892.9 1.46 0.14 41.0156 0.9766 - 252.08 KB
CalculateInDatabase 627.1 14.58 42.54 626.4 1.00 0.00 4.8828 - - 33.27 KB

你可能感兴趣的:(EF Core的入门使用总结)