如何设置EF Core中的数据模型配置?

2026-05-06 07:181阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计2760个文字,预计阅读时间需要12分钟。

如何设置EF Core中的数据模型配置?

0. 前言,本文的第一节将概述配置模型的作用(对数据模型的补充描述)。+第二节描述两种配置方式,即数据注释(data annotations)和Fluent API方式。+第三节开始,主要介绍如何将常用的配置‘嵌入’。

0 前言

本文的第一节,会概述配置模型的作用(对数据模型的补充描述)。

第二节描述两种配置方式,即:数据注释(data annotations)和 Fluent API 方式。

第三节开始,主要是将常用的配置记录下来,以便翻查。


1 概述

数据实体(Entity)的类名、属性等,称之为约定(conventions),约定主要是为了定义数据模型(Model)的形状。

但是光靠约定可能不足以完整描述数据模型,有时我们的数据模型与我们的数据实体可能也有差异,这时,就可以通过数据注释(data annotations)和 Fluent API 补充,具体请参考EF Core官方文档:创建并配置模型。


2 配置方式 2.1 数据注释(data annotations)

直接在数据实体上打上对应的标签,如下例子中,标识表名为 Blogs,Url 属性不能为 null

[Table("Blogs")] public class Blog { public int BlogId { get; set; } [Required] public string Url { get; set; } }

注意:数据注释的方式的优先级高于约定(conventions)但低于 Fluent API,即数据注释的方式会被 Fluent API 覆盖。

如何设置EF Core中的数据模型配置?

2.2 Fluent API

对描述数据模型(Model)具有最高优先级。

通过在派生的 DbContext 中,重写 OnModelCreating 方法,并使用 ModelBuilder API 来配置模型。

internal class MyContext : DbContext { public DbSet<Blog> Blogs { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { // 写法1:链式配置 modelBuilder.Entity<Blog>() .ToTable("Blogs") .Property(b => b.Url).IsRequired(); // 写法2:委托函数配置 modelBuilder.Entity<Post>(eb => { eb.ToTable("Posts"); eb.Property(b => b.Title).IsRequired(); }); } } 2.2.1 分组配置

可以实现类似于批量配置,具体请参考分组配置。

modelBuilder.ApplyConfigurationsFromAssembly(typeof(BlogEntityTypeConfiguration).Assembly);

注意:应用配置的顺序是不确定的,因此仅当顺序不重要时才应使用此方法。

3 配置数据模型 3.1 在模型中包含类型

在上下文中包含于 DbSet 的类意味着它包含在 EF Core 的模型中;我们通常将这些类称为实体。 EF Core 可以向数据库中读写实体实例,如果使用的是关系数据库,EF Core 可以通过迁移为实体创建表。

3.1.1 迁移时,创建表的情况

使用 EF Core 添加迁移时,哪些实体会被创建表呢?包含以下三种情况:

  1. 在 DbContext 的 DbSet 属性中公开的实体类
  2. 在 DbContext 的 OnModelCreating 方法中指定的实体类
  3. 以上两种情况的实体类内,通过递归探索导航属性发现的实体类

下面是一个官方示例:

下面的代码示例中,数据模型中包含的实体类有:

  • 包含 Blog,因为它在上下文的 DbSet 属性中公开。
  • 包含 Post,因为它是通过 Blog.Posts 导航属性发现的。
  • 包含 AuditEntry因为它是 OnModelCreating 中指定的。

internal class MyContext : DbContext { public DbSet<Blog> Blogs { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<AuditEntry>(); } } 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 Blog Blog { get; set; } } public class AuditEntry { public int AuditEntryId { get; set; } public string Username { get; set; } public string Action { get; set; } } 3.2 配置实体类型(Entity types) 3.2.1 数据注释(data annotations)

//从模型(model)中排除类型(class) [NotMapped] //指定表名称 [Table("blogs")] //指定架构(scheme) [Table("blogs", Schema = "blogging")] //表注释 [Comment("Blogs managed on the website")] 3.2.2 Fluent API

//从模型(model)中排除类型(class) modelBuilder.Ignore<BlogMetadata>(); //从迁移中排除,生成迁移将不会包含 表AspNetUsers,但 IdentityUser 仍在模型中 modelBuilder.Entity<IdentityUser>().ToTable("AspNetUsers", t => t.ExcludeFromMigrations()); //指定表名称 modelBuilder.Entity<Blog>().ToTable("blogs"); //指定架构(scheme) modelBuilder.Entity<Blog>().ToTable("blogs", schema: "blogging"); //通用配置:默认架构名 modelBuilder.HasDefaultSchema("blogging"); //视图映射 //映射到视图将删除默认表映射,但从 EF 5.0 开始,实体类型也可以显式映射到表。 在这种情况下,查询映射将用于查询,表映射将用于更新。 modelBuilder.Entity<Blog>().ToView("blogsView", schema: "blogging"); //表注释 modelBuilder.Entity<Blog>().HasComment("Blogs managed on the website"); //表值函数映射 modelBuilder.Entity<BlogWithMultiplePosts>().HasNoKey().ToFunction("BlogsWithMultiplePosts"); //共享类型实体(Shared-type entity types) //不理解 //docs.microsoft.com/zh-cn/ef/core/modeling/entity-types?tabs=data-annotations#shared-type-entity-types 3.3 配置实体属性(Entity properties) 3.3.1 数据注释(data annotations)

//排除属性 [NotMapped] //备注 [Comment("The URL of the blog")] [Column("blog_id")] [Column(TypeName = "varchar(200)")] [MaxLength(500)] //精度和小数位 [Precision(14, 2)] public decimal Score { get; set; } [Precision(3)] public DateTime LastUpdated { get; set; } //nvarchar 表示 Unicode 数据,varchar 表示非 Unicode 数据 [Unicode(false)] [Required] //列排序 //默认情况下,在使用迁移创建表时,EF Core 首先为主键列排序,然后为实体类型和从属类型的属性排序,最后为基类型中的属性排序。(顺序:主键 >> 属性 >> 基类属性) //在一般情况下,大多数数据库仅支持在创建表时对列进行排序。 这意味着不能使用列顺序特性对现有表中的列进行重新排序。 [Column(Order = 0)] [Column(Order = 1)] 3.3.2 Fluent API

//排除属性 modelBuilder.Entity<Blog>().Ignore(b => b.LoadedFromDatabase); //备注 modelBuilder.Entity<Blog>().Property(b => b.Url).HasComment("The URL of the blog"); modelBuilder.Entity<Blog>().Property(b => b.BlogId).HasColumnName("blog_id"); modelBuilder.Entity<Blog>().Property(b => b.Url).HasColumnType("varchar(200)"); modelBuilder.Entity<Blog>().Property(b => b.Url).HasMaxLength(500); //精度和小数位 modelBuilder.Entity<Blog>().Property(b => b.Score).HasPrecision(14, 2); modelBuilder.Entity<Blog>().Property(b => b.LastUpdated).HasPrecision(3); //nvarchar 表示 Unicode 数据,varchar 表示非 Unicode 数据 modelBuilder.Entity<Book>().Property(b => b.Isbn).IsUnicode(false); modelBuilder.Entity<Blog>().Property(b => b.Url).IsRequired(); //可以定义文本列的排序规则,以确定如何比较和排序。 //排序规则:docs.microsoft.com/zh-cn/ef/core/miscellaneous/collations-and-case-sensitivity //例如,以下代码片段将 SQL Server 列配置为不区分大小写 modelBuilder.Entity<Customer>().Property(c => c.Name) .UseCollation("SQL_Latin1_General_CP1_CI_AS"); modelBuilder.Entity<Employee>().Property(b => b.Id).HasColumnOrder(0); modelBuilder.Entity<Employee>().Property(b => b.FirstName).HasColumnOrder(1); 3.4 配置主键、外键、索引 3.4.1 数据注释

//主键 [Key] //无主键 [Keyless] //外键 [ForeignKey] //反向属性:docs.microsoft.com/zh-cn/ef/core/modeling/relationships?tabs=data-annotations%2Cfluent-api-simple-key%2Csimple-key#manual-configuration [InverseProperty("Author")] //索引 [Index(nameof(Url))] public class Blog { public int BlogId { get; set; } public string Url { get; set; } } //复合索引 [Index(nameof(FirstName), nameof(LastName))] //唯一索引 [Index(nameof(Url), IsUnique = true)] //索引名称 [Index(nameof(Url), Name = "Index_Url")] 3.4.2 Fluent API

//主键 modelBuilder.Entity<Car>().HasKey(c => c.LicensePlate); //复合主键 modelBuilder.Entity<Car>().HasKey(c => new { c.State, c.LicensePlate }); //无主键 modelBuilder.Entity<BlogPostsCount>().HasNoKey(); //备选键:docs.microsoft.com/zh-cn/ef/core/modeling/keys?tabs=fluent-api#alternate-keys //备选键 HasPrincipalKey modelBuilder.Entity<Post>() .HasOne(p => p.Blog) .WithMany(b => b.Posts) .HasForeignKey(p => p.BlogUrl) .HasPrincipalKey(b => b.Url); //将单个属性配置为备选键 modelBuilder.Entity<Car>() .HasAlternateKey(c => c.LicensePlate); //复合备选键 modelBuilder.Entity<Car>() .HasAlternateKey(c => new { c.State, c.LicensePlate }); //配置备选键的索引和唯一约束的名称 modelBuilder.Entity<Car>() .HasAlternateKey(c => c.LicensePlate) .HasName("AlternateKey_LicensePlate"); //配置关系 modelBuilder.Entity<Post>() .HasOne(p => p.Blog) .WithMany(b => b.Posts); //配置外键 modelBuilder.Entity<Post>() .HasOne(p => p.Blog) .WithMany(b => b.Posts) .HasForeignKey(p => p.BlogForeignKey); //配置外键约束的名称 modelBuilder.Entity<Post>() .HasOne(p => p.Blog) .WithMany(b => b.Posts) .HasForeignKey(p => p.BlogId) .HasConstraintName("ForeignKey_Post_Blog"); //关系:docs.microsoft.com/zh-cn/ef/core/modeling/relationships //索引 modelBuilder.Entity<Blog>().HasIndex(b => b.Url); modelBuilder.Entity<Person>().HasIndex(p => new { p.FirstName, p.LastName }); //唯一索引 modelBuilder.Entity<Blog>().HasIndex(b => b.Url).IsUnique(); //索引名称 modelBuilder.Entity<Blog>().HasIndex(b => b.Url).HasDatabaseName("Index_Url"); //索引筛选器:docs.microsoft.com/zh-cn/ef/core/modeling/indexes?tabs=fluent-api#index-filter modelBuilder.Entity<Blog>().HasIndex(b => b.Url).HasFilter("[Url] IS NOT NULL"); //包含列:SQL Server 的 Include 关键字 modelBuilder.Entity<Post>().HasIndex(p => p.Url) .IncludeProperties(p => new { p.Title, p.PublishedOn }); //检查约束 modelBuilder.Entity<Product>().HasCheckConstraint("CK_Prices", "[Price] > [DiscountedPrice]", c => c.HasName("CK_Product_Prices")); 3.5 值转换(value conversions) 3.5.1 基本配置

假设将一个枚举和实体类型定义为:

public class Rider { public int Id { get; set; } public EquineBeast Mount { get; set; } } public enum EquineBeast { Donkey, Mule, Horse, Unicorn }

可以将枚举值(如字符串 "Donkey"、"Mule"等)存储在数据库中。

需要配置两个函数:

protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder .Entity<Rider>() .Property(e => e.Mount) .HasConversion( v => v.ToString(), v => (EquineBeast)Enum.Parse(typeof(EquineBeast), v)); } 3.5.2 批量配置

public class CurrencyConverter : ValueConverter<Currency, decimal> { public CurrencyConverter() : base( v => v.Amount, v => new Currency(v)) { } }

配置

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { configurationBuilder .Properties<Currency>() .HaveConversion<CurrencyConverter>(); } 3.5.3 ValueConverter 类

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); } 3.5.4 内置转换器

下面是一个示例,更多的请翻查官方文档:内置转换器

protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder .Entity<Rider>() .Property(e => e.Mount) .HasConversion<string>(); }
4 数据种子(data seeding)

OnModelCreating 中配置种子数据:

modelBuilder.Entity<Blog>().HasData(new Blog { BlogId = 1, Url = "sample.com" });

匿名对象:

modelBuilder.Entity<Post>().HasData( new { BlogId = 1, PostId = 2, Title = "Second post", Content = "Test 2" });

多行数据

modelBuilder.Entity<Post>().OwnsOne(p => p.AuthorName).HasData( new { PostId = 1, First = "Andriy", Last = "Svyryd" }, new { PostId = 2, First = "Diego", Last = "Vega" });
参考来源

EF Core官方文档:创建模型

本文共计2760个文字,预计阅读时间需要12分钟。

如何设置EF Core中的数据模型配置?

0. 前言,本文的第一节将概述配置模型的作用(对数据模型的补充描述)。+第二节描述两种配置方式,即数据注释(data annotations)和Fluent API方式。+第三节开始,主要介绍如何将常用的配置‘嵌入’。

0 前言

本文的第一节,会概述配置模型的作用(对数据模型的补充描述)。

第二节描述两种配置方式,即:数据注释(data annotations)和 Fluent API 方式。

第三节开始,主要是将常用的配置记录下来,以便翻查。


1 概述

数据实体(Entity)的类名、属性等,称之为约定(conventions),约定主要是为了定义数据模型(Model)的形状。

但是光靠约定可能不足以完整描述数据模型,有时我们的数据模型与我们的数据实体可能也有差异,这时,就可以通过数据注释(data annotations)和 Fluent API 补充,具体请参考EF Core官方文档:创建并配置模型。


2 配置方式 2.1 数据注释(data annotations)

直接在数据实体上打上对应的标签,如下例子中,标识表名为 Blogs,Url 属性不能为 null

[Table("Blogs")] public class Blog { public int BlogId { get; set; } [Required] public string Url { get; set; } }

注意:数据注释的方式的优先级高于约定(conventions)但低于 Fluent API,即数据注释的方式会被 Fluent API 覆盖。

如何设置EF Core中的数据模型配置?

2.2 Fluent API

对描述数据模型(Model)具有最高优先级。

通过在派生的 DbContext 中,重写 OnModelCreating 方法,并使用 ModelBuilder API 来配置模型。

internal class MyContext : DbContext { public DbSet<Blog> Blogs { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { // 写法1:链式配置 modelBuilder.Entity<Blog>() .ToTable("Blogs") .Property(b => b.Url).IsRequired(); // 写法2:委托函数配置 modelBuilder.Entity<Post>(eb => { eb.ToTable("Posts"); eb.Property(b => b.Title).IsRequired(); }); } } 2.2.1 分组配置

可以实现类似于批量配置,具体请参考分组配置。

modelBuilder.ApplyConfigurationsFromAssembly(typeof(BlogEntityTypeConfiguration).Assembly);

注意:应用配置的顺序是不确定的,因此仅当顺序不重要时才应使用此方法。

3 配置数据模型 3.1 在模型中包含类型

在上下文中包含于 DbSet 的类意味着它包含在 EF Core 的模型中;我们通常将这些类称为实体。 EF Core 可以向数据库中读写实体实例,如果使用的是关系数据库,EF Core 可以通过迁移为实体创建表。

3.1.1 迁移时,创建表的情况

使用 EF Core 添加迁移时,哪些实体会被创建表呢?包含以下三种情况:

  1. 在 DbContext 的 DbSet 属性中公开的实体类
  2. 在 DbContext 的 OnModelCreating 方法中指定的实体类
  3. 以上两种情况的实体类内,通过递归探索导航属性发现的实体类

下面是一个官方示例:

下面的代码示例中,数据模型中包含的实体类有:

  • 包含 Blog,因为它在上下文的 DbSet 属性中公开。
  • 包含 Post,因为它是通过 Blog.Posts 导航属性发现的。
  • 包含 AuditEntry因为它是 OnModelCreating 中指定的。

internal class MyContext : DbContext { public DbSet<Blog> Blogs { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<AuditEntry>(); } } 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 Blog Blog { get; set; } } public class AuditEntry { public int AuditEntryId { get; set; } public string Username { get; set; } public string Action { get; set; } } 3.2 配置实体类型(Entity types) 3.2.1 数据注释(data annotations)

//从模型(model)中排除类型(class) [NotMapped] //指定表名称 [Table("blogs")] //指定架构(scheme) [Table("blogs", Schema = "blogging")] //表注释 [Comment("Blogs managed on the website")] 3.2.2 Fluent API

//从模型(model)中排除类型(class) modelBuilder.Ignore<BlogMetadata>(); //从迁移中排除,生成迁移将不会包含 表AspNetUsers,但 IdentityUser 仍在模型中 modelBuilder.Entity<IdentityUser>().ToTable("AspNetUsers", t => t.ExcludeFromMigrations()); //指定表名称 modelBuilder.Entity<Blog>().ToTable("blogs"); //指定架构(scheme) modelBuilder.Entity<Blog>().ToTable("blogs", schema: "blogging"); //通用配置:默认架构名 modelBuilder.HasDefaultSchema("blogging"); //视图映射 //映射到视图将删除默认表映射,但从 EF 5.0 开始,实体类型也可以显式映射到表。 在这种情况下,查询映射将用于查询,表映射将用于更新。 modelBuilder.Entity<Blog>().ToView("blogsView", schema: "blogging"); //表注释 modelBuilder.Entity<Blog>().HasComment("Blogs managed on the website"); //表值函数映射 modelBuilder.Entity<BlogWithMultiplePosts>().HasNoKey().ToFunction("BlogsWithMultiplePosts"); //共享类型实体(Shared-type entity types) //不理解 //docs.microsoft.com/zh-cn/ef/core/modeling/entity-types?tabs=data-annotations#shared-type-entity-types 3.3 配置实体属性(Entity properties) 3.3.1 数据注释(data annotations)

//排除属性 [NotMapped] //备注 [Comment("The URL of the blog")] [Column("blog_id")] [Column(TypeName = "varchar(200)")] [MaxLength(500)] //精度和小数位 [Precision(14, 2)] public decimal Score { get; set; } [Precision(3)] public DateTime LastUpdated { get; set; } //nvarchar 表示 Unicode 数据,varchar 表示非 Unicode 数据 [Unicode(false)] [Required] //列排序 //默认情况下,在使用迁移创建表时,EF Core 首先为主键列排序,然后为实体类型和从属类型的属性排序,最后为基类型中的属性排序。(顺序:主键 >> 属性 >> 基类属性) //在一般情况下,大多数数据库仅支持在创建表时对列进行排序。 这意味着不能使用列顺序特性对现有表中的列进行重新排序。 [Column(Order = 0)] [Column(Order = 1)] 3.3.2 Fluent API

//排除属性 modelBuilder.Entity<Blog>().Ignore(b => b.LoadedFromDatabase); //备注 modelBuilder.Entity<Blog>().Property(b => b.Url).HasComment("The URL of the blog"); modelBuilder.Entity<Blog>().Property(b => b.BlogId).HasColumnName("blog_id"); modelBuilder.Entity<Blog>().Property(b => b.Url).HasColumnType("varchar(200)"); modelBuilder.Entity<Blog>().Property(b => b.Url).HasMaxLength(500); //精度和小数位 modelBuilder.Entity<Blog>().Property(b => b.Score).HasPrecision(14, 2); modelBuilder.Entity<Blog>().Property(b => b.LastUpdated).HasPrecision(3); //nvarchar 表示 Unicode 数据,varchar 表示非 Unicode 数据 modelBuilder.Entity<Book>().Property(b => b.Isbn).IsUnicode(false); modelBuilder.Entity<Blog>().Property(b => b.Url).IsRequired(); //可以定义文本列的排序规则,以确定如何比较和排序。 //排序规则:docs.microsoft.com/zh-cn/ef/core/miscellaneous/collations-and-case-sensitivity //例如,以下代码片段将 SQL Server 列配置为不区分大小写 modelBuilder.Entity<Customer>().Property(c => c.Name) .UseCollation("SQL_Latin1_General_CP1_CI_AS"); modelBuilder.Entity<Employee>().Property(b => b.Id).HasColumnOrder(0); modelBuilder.Entity<Employee>().Property(b => b.FirstName).HasColumnOrder(1); 3.4 配置主键、外键、索引 3.4.1 数据注释

//主键 [Key] //无主键 [Keyless] //外键 [ForeignKey] //反向属性:docs.microsoft.com/zh-cn/ef/core/modeling/relationships?tabs=data-annotations%2Cfluent-api-simple-key%2Csimple-key#manual-configuration [InverseProperty("Author")] //索引 [Index(nameof(Url))] public class Blog { public int BlogId { get; set; } public string Url { get; set; } } //复合索引 [Index(nameof(FirstName), nameof(LastName))] //唯一索引 [Index(nameof(Url), IsUnique = true)] //索引名称 [Index(nameof(Url), Name = "Index_Url")] 3.4.2 Fluent API

//主键 modelBuilder.Entity<Car>().HasKey(c => c.LicensePlate); //复合主键 modelBuilder.Entity<Car>().HasKey(c => new { c.State, c.LicensePlate }); //无主键 modelBuilder.Entity<BlogPostsCount>().HasNoKey(); //备选键:docs.microsoft.com/zh-cn/ef/core/modeling/keys?tabs=fluent-api#alternate-keys //备选键 HasPrincipalKey modelBuilder.Entity<Post>() .HasOne(p => p.Blog) .WithMany(b => b.Posts) .HasForeignKey(p => p.BlogUrl) .HasPrincipalKey(b => b.Url); //将单个属性配置为备选键 modelBuilder.Entity<Car>() .HasAlternateKey(c => c.LicensePlate); //复合备选键 modelBuilder.Entity<Car>() .HasAlternateKey(c => new { c.State, c.LicensePlate }); //配置备选键的索引和唯一约束的名称 modelBuilder.Entity<Car>() .HasAlternateKey(c => c.LicensePlate) .HasName("AlternateKey_LicensePlate"); //配置关系 modelBuilder.Entity<Post>() .HasOne(p => p.Blog) .WithMany(b => b.Posts); //配置外键 modelBuilder.Entity<Post>() .HasOne(p => p.Blog) .WithMany(b => b.Posts) .HasForeignKey(p => p.BlogForeignKey); //配置外键约束的名称 modelBuilder.Entity<Post>() .HasOne(p => p.Blog) .WithMany(b => b.Posts) .HasForeignKey(p => p.BlogId) .HasConstraintName("ForeignKey_Post_Blog"); //关系:docs.microsoft.com/zh-cn/ef/core/modeling/relationships //索引 modelBuilder.Entity<Blog>().HasIndex(b => b.Url); modelBuilder.Entity<Person>().HasIndex(p => new { p.FirstName, p.LastName }); //唯一索引 modelBuilder.Entity<Blog>().HasIndex(b => b.Url).IsUnique(); //索引名称 modelBuilder.Entity<Blog>().HasIndex(b => b.Url).HasDatabaseName("Index_Url"); //索引筛选器:docs.microsoft.com/zh-cn/ef/core/modeling/indexes?tabs=fluent-api#index-filter modelBuilder.Entity<Blog>().HasIndex(b => b.Url).HasFilter("[Url] IS NOT NULL"); //包含列:SQL Server 的 Include 关键字 modelBuilder.Entity<Post>().HasIndex(p => p.Url) .IncludeProperties(p => new { p.Title, p.PublishedOn }); //检查约束 modelBuilder.Entity<Product>().HasCheckConstraint("CK_Prices", "[Price] > [DiscountedPrice]", c => c.HasName("CK_Product_Prices")); 3.5 值转换(value conversions) 3.5.1 基本配置

假设将一个枚举和实体类型定义为:

public class Rider { public int Id { get; set; } public EquineBeast Mount { get; set; } } public enum EquineBeast { Donkey, Mule, Horse, Unicorn }

可以将枚举值(如字符串 "Donkey"、"Mule"等)存储在数据库中。

需要配置两个函数:

protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder .Entity<Rider>() .Property(e => e.Mount) .HasConversion( v => v.ToString(), v => (EquineBeast)Enum.Parse(typeof(EquineBeast), v)); } 3.5.2 批量配置

public class CurrencyConverter : ValueConverter<Currency, decimal> { public CurrencyConverter() : base( v => v.Amount, v => new Currency(v)) { } }

配置

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { configurationBuilder .Properties<Currency>() .HaveConversion<CurrencyConverter>(); } 3.5.3 ValueConverter 类

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); } 3.5.4 内置转换器

下面是一个示例,更多的请翻查官方文档:内置转换器

protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder .Entity<Rider>() .Property(e => e.Mount) .HasConversion<string>(); }
4 数据种子(data seeding)

OnModelCreating 中配置种子数据:

modelBuilder.Entity<Blog>().HasData(new Blog { BlogId = 1, Url = "sample.com" });

匿名对象:

modelBuilder.Entity<Post>().HasData( new { BlogId = 1, PostId = 2, Title = "Second post", Content = "Test 2" });

多行数据

modelBuilder.Entity<Post>().OwnsOne(p => p.AuthorName).HasData( new { PostId = 1, First = "Andriy", Last = "Svyryd" }, new { PostId = 2, First = "Diego", Last = "Vega" });
参考来源

EF Core官方文档:创建模型