美文网首页
EF Core的入门使用总结

EF Core的入门使用总结

作者: 谁有羊毛 | 来源:发表于2021-04-12 11:15 被阅读0次

    一、初步使用

    1. 依赖注入设置
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
    
        services.AddDbContext<ApplicationDbContext>(
            options => options.UseSqlServer("name=ConnectionStrings:DefaultConnection"));
    }
    
    1. 创建DbContext
    public class ApplicationDbContext : DbContext
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> 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<Post> Posts { get; } = new List<Post>();
    }
    
    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<Blog> Blogs { get; set; }
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<AuditEntry>();
        }
    }
    
    1. 忽略某个类型
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Ignore<BlogMetadata>();
    }
    
    1. 忽略/排除属性
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .Ignore(b => b.LoadedFromDatabase);
    }
    
    1. 指定表名
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .ToTable("blogs");
    }
    
    1. 配置列名
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .Property(b => b.BlogId)
            .HasColumnName("blog_id");
    }
    
    1. 配置列的数据类型
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>(
            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<Blog>()
            .Property(b => b.Url)
            .HasMaxLength(500);
    }
    
    1. 显示配置必须的
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .Property(b => b.Url)
            .IsRequired();
    }
    
    1. 排序规则
    modelBuilder.Entity<Customer>().Property(c => c.Name)
        .UseCollation("SQL_Latin1_General_CP1_CI_AS");
    
    1. 配置主键
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Car>()
            .HasKey(c => c.LicensePlate);
    }
    //配置主键约束名称
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .HasKey(b => b.BlogId)
            .HasName("PrimaryKey_BlogId");
    }
    

    三、Fluent Api 生成默认值

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

    四、实体之间的关系

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

    1. 单个导航属性
    internal class MyContext : DbContext
    {
        public DbSet<Blog> Blogs { get; set; }
        public DbSet<Post> Posts { get; set; }
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Blog>()
                .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<Blog> Blogs { get; set; }
        public DbSet<Post> Posts { get; set; }
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Post>()
                .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<Post> 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<Post>()
            .HasOne(p => p.Blog)
            .WithMany(b => b.Posts)
            .OnDelete(DeleteBehavior.Cascade);
    }
    
    1. 1对1关系
    
     protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Blog>()
                .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<MyContext> options)
            : base(options)
        {
        }
    
        public DbSet<Post> Posts { get; set; }
        public DbSet<Tag> Tags { get; set; }
    
        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.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<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 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<Blog>()
            .HasIndex(b => b.Url);
    }
    
    1. 复合索引
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Person>()
            .HasIndex(p => new { p.FirstName, p.LastName });
    }
    
    1. 唯一索引
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .HasIndex(b => b.Url)
            .IsUnique();
    }
    

    六、值类型转换

    1. 把某个字段存为字符串,借而取的时候转换为对象
    modelBuilder.Entity<TaskRule.Domain.TaskRules.TaskRule>()
                            .Property(e => e.UrlConfig)
                            .HasConversion(v => JsonConvert.SerializeObject(v), 
                                           s => JsonConvert.DeserializeObject<UrlConfig>(s));
    
    1. 内置转换器
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    { 
        //把一个int类型转为bool类型
        modelBuilder
            .Entity<User>()
            .Property(e => e.IsActive)
            .HasConversion<int>();
    }
    
    1. 定义一个Converter
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        var converter = new ValueConverter<EquineBeast, string>(
            v => v.ToString(),
            v => (EquineBeast)Enum.Parse(typeof(EquineBeast), v));
    
        modelBuilder
            .Entity<Rider>()
            .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)—— 每个之类都建一个表。子类的表的列会包含它继承的父类的所有字段

    八、性能诊断

    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的入门使用总结

          本文链接:https://www.haomeiwen.com/subject/phvvkltx.html