.Net Core 之 Entity Framework Core -- Code Frist 数据注解及Fluent API

只有学习,内心才能踏实。

今天来总结一下,EF Core 中Code Frist 的数据注解及 Fluent API。其实这个次总结是为了巩固一下以前的知识,如果比较懂EF ,这部知识可以快速过。但是!但是!EF Core 和 EF 还是有很大区别的,比如说:默认值和索引等用数据注解的方式在.Net Core 无效,只能用Fluent API. 本文记录两种方式来创建模型,分别是数据注解方式和Fluent API

在这里有很多东西可以扩展,但是由于本人能力有限,无法求证。文末会总结遗留的问题,有大神看到可以帮忙回答一下。EF Core 的版本为2.1


1.表映射 [Table(string name, Properties:[Schema = string])

[Table("DataTest", Schema = "admin")]
 //注释:[Table(string name, Properties:[Schema = string])
 public class DataAnnotationsAttribute
 {
      [Key]
      [Column(Order = 1)]
      public int Id { get; set; }
}

2.列映射 [Column (string name, Properties:[Order = int],[TypeName = string]) 

  [Table("DataTest", Schema = "admin")]
        //注释:[Table(string name, Properties:[Schema = string])
        public class DataAnnotationsAttribute
        {
            [Key]
            [Column(Order = 1)]
            public int Id { get; set; }

            [Column(Order = 3, TypeName = "varchar(50)")]
            public string Name { get; set; }

            [Column("FullName", Order = 2, TypeName = "varchar(60)")]
            // [Column (string name, Properties:[Order = int],[TypeName = string])
            public string FullName { get; set; }

            // [ForeignKey] 参考 UserRole
            [DefaultValue(3)]
            public int DefaultValue { get; set; }
        }

Fluent API 

protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity(eb =>
        {
            eb.Property(b => b.Name).HasColumnType("varchar(50)");
            eb.Property(b => b.FullName).HasColumnType("varchar(60)");
        });
    }

 

.Net Core 之 Entity Framework Core -- Code Frist 数据注解及Fluent API_第1张图片

 

数据类型:这点,有时间的话,可以从网上查看一下啊,EF 的数据类型 对应数据库的数据类型

3. 主键 [key]

数据注解方式:
[Key]
[Column(Order = 1)]
 public int Id { get; set; }

Fluent API

 protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity() .HasKey(b => b.BlogId).HasName("PrimaryKey_BlogId");
    }

数据库图:略

4. 复合主键

Fluent API

 protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
         modelBuilder.Entity().HasKey(c => new { c.LicensePlate, c.State });
    }

5. 计算列(列计算或拼接):数据注解中无法实现,只能在Fluent API中实现

class MyContext : DbContext
{
    public DbSet People { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity()
            .Property(p => p.DisplayName)
            .HasComputedColumnSql("[LastName] + ', ' + [FirstName]");
    }
}

public class Person
{
    public int PersonId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string DisplayName { get; set; }
}

数据库图:略

 6.序列:数据注解中无法实现,只能在Fluent API中实现

你可以配置它如其实值从1000 开始:StartsAt(1000);每次增5:IncrementsBy(5)

也可以从模型中取值,比如下面 NEXT VALUE FOR shared.OrderNumbers

class MyContext : DbContext
{
    public DbSet Orders { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.HasSequence("OrderNumbers", schema: "shared")
            .StartsAt(1000)
            .IncrementsBy(5);

        modelBuilder.Entity()
            .Property(o => o.OrderNo)
            .HasDefaultValueSql("NEXT VALUE FOR shared.OrderNumbers");
    }
}

public class Order
{
    public int OrderId { get; set; }
    public int OrderNo { get; set; }
    public string Url { get; set; }
}

7.默认值:数据注解中无法实现(跟EF 不一样,即使提供,但没有效果),只能在Fluent API中实现

字段上加[DefaultValue(3)] 是没有效果的

class MyContext : DbContext
{
    public DbSet Blogs { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity()
            .Property(b => b.Rating)
            .HasDefaultValue(3);
    }
}

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

8.索引:数据注解中无法实现(跟EF 不一样,即使提供,但没有效果),只能在Fluent API中实现

是否唯一:IsUnique()

IsClustered 在.net core 没有发现本人不敢确认有没有

protected override void OnModelCreating(ModelBuilder modelBuilder)
 {
    // 唯一索引
     modelBuilder.Entity().HasIndex(b => b.Url).IsUnique();
    // 非唯一
     modelBuilder.Entity().HasIndex(b => new { b.RegistrationNumber1, b.RegistrationNumber2 });
}

.Net Core 之 Entity Framework Core -- Code Frist 数据注解及Fluent API_第2张图片

9:外键约束

一对多:

// 实体
public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }

    public int CurrentGradeId { get; set; }
    public Grade Grade { get; set; }
}

public class Grade
{
    public int GradeId { get; set; }
    public string GradeName { get; set; }
    public string Section { get; set; }

    public ICollection Students { get; set; }
}
// Fluent API
protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity()
            .HasOne(s => s.Grade)
            .WithMany(g => g.Students)
            .HasForeignKey(s => s.CurrentGradeId);
    }

    public DbSet Grades { get; set; }
    public DbSet Students { get; set; }

.Net Core 之 Entity Framework Core -- Code Frist 数据注解及Fluent API_第3张图片

一对一:

// 实体
public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
       
    public StudentAddress Address { get; set; }
}

public class StudentAddress
{
    public int StudentAddressId { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Country { get; set; }

    public int AddressOfStudentId { get; set; }
    public Student Student { get; set; }
}
//Fluent API
protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity()
            .HasOne(s => s.Address)
            .WithOne(ad => ad.Student)
            .HasForeignKey(ad => ad.AddressOfStudentId);
    }

    public DbSet Students { get; set; }
    public DbSet StudentAddresses { get; set; }

.Net Core 之 Entity Framework Core -- Code Frist 数据注解及Fluent API_第4张图片

多对多:

// 实体
public class StudentCourse
{
    public int StudentId { get; set; }
    public Student Student { get; set; }

    public int CourseId { get; set; }
    public Course Course { get; set; }
}
public class Student
{
    public int StudentId { get; set; }
    public string Name { get; set; }

    public IList StudentCourses { get; set; }
}

public class Course
{
    public int CourseId { get; set; }
    public string CourseName { get; set; }
    public string Description { get; set; }

    public IList StudentCourses { get; set; }
}
// Fluent API

modelBuilder.Entity().HasKey(sc => new { sc.SId, sc.CId });

modelBuilder.Entity()
    .HasOne(sc => sc.Student)
    .WithMany(s => s.StudentCourses)
    .HasForeignKey(sc => sc.SId);


modelBuilder.Entity()
    .HasOne(sc => sc.Course)
    .WithMany(s => s.StudentCourses)
    .HasForeignKey(sc => sc.CId);

 10:排除实体和属性--NotMapped

// 实体
////排除entity
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public BlogMetadata Metadata { get; set; }
}

[NotMapped]
public class BlogMetadata
{
    public DateTime LoadedFromDatabase { get; set; }
}
////排除属性
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    [NotMapped]
    public DateTime LoadedFromDatabase { get; set; }
}
//Fluent API
//// 排除entity
 protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Ignore();
    }
//// 排除属性
 protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity()
            .Ignore(b => b.LoadedFromDatabase);
    }

11:最大长度--MaxLength  (Fluent API 中没有MinLength)

//实体
public class Blog
{
    public int BlogId { get; set; }
    [MaxLength(500)]
    public string Url { get; set; }
}

//Fluent API
 protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity()
            .Property(b => b.Url)
            .HasMaxLength(500);
    }

12:防并发:Timestamp 与ConcurrencyCheck

//实体
public class Person
{
    public int PersonId { get; set; }

    [ConcurrencyCheck]
    public string LastName { get; set; }

    //10 .Timestamp 时间戳必须是byte[]类型的,防止并发,EF 的并发都是乐观的。例如同时改一条数据,别人在你之前提交
    [Timestamp]
    public byte[] Timestamp { get; set; }
}
//Fluent API

protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity()
            .Property(p => p.Timestamp)
            .IsRowVersion();
     modelBuilder.Entity().Property(b => b.Timestamp).IsRowVersion();
    }

13: 值转换  (.net core 2.1 新增)

和14 一起举例在进行数据库迁移时,EF会往数据库中插入一些数据

14:Data Seeding  (.net core 2.1 新增)这个是用来初始化数据用。

// 值类型转换
public class Blog
{
    public int BlogId { get; set; }
     public string Url { get; set; }
    public EquineBeast Mount { get; set; }
}

public enum EquineBeast
{
    Donkey,
    Mule,
    Horse,
    Unicorn
}
// fluent api 
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity()
        .Property(e => e.Mount)
        .HasConversion(
            v => v.ToString(),
            v => (EquineBeast)Enum.Parse(typeof(EquineBeast), v));
    // DATA SEEDING
    modelBuilder.Entity().HasData(new Blog { BlogId = 1, Url = "http://sample.com" });

}

数据迁移后的结果是:

.Net Core 之 Entity Framework Core -- Code Frist 数据注解及Fluent API_第5张图片

除了基本的枚举转字符串以外,EF Core还提供如下的转换类:

BoolToZeroOneConverter 将布尔值转换为0或1
BoolToStringConverter 将布尔值转换为字符串(Y或N)
BoolToTwoValuesConverter 将布尔值转换为指定的两个值(没搞明白干嘛用的)
BytesToStringConverter 将字节数组转换为Base64编码的字符串
CastingConverter 从一种类型转换到另一种类型(可以被C#互相转换的类型)
CharToStringConverter char转为string
DateTimeOffsetToBinaryConverter DateTimeOffset转为二进制的64位的值
DateTimeOffsetToBytesConverter DateTimeOffset转为字节数组
DateTimeOffsetToStringConverter DateTimeOffset转为字符串
DateTimeToBinaryConverter DateTime转为带有DateTimeKind的64位的值
DateTimeToStringConverter DateTime转为字符串
DateTimeToTicksConverter DateTime转为ticks
EnumToNumberConverter 枚举转数字
EnumToStringConverter 枚举转字符串
GuidToBytesConverter Guid转字节数组
GuidToStringConverter Guid转字符串
NumberToBytesConverter 数字转字节数组
NumberToStringConverter 数字转字符串
StringToBytesConverter 字符串转字节数组
TimeSpanToStringConverter TimeSpan转字符串
TimeSpanToTicksConverter TimeSpan转ticks

 

上面的这些对象的使用方式如下:

var converter = new EnumToStringConverter();
builder.Property(p => p.Gender).HasConversion(converter);

除了这种方式外,EF Core也支持直接指定类型,如:

builder.Property(p => p.Gender).HasConversion(string);

需要注意的是,不能将null进行转换,一个属性只能对应一个列做转换。

15:查询类型-Query Types  (.net core 2.1 新增)

ToView等

这就不多写了,我感觉比较重要,怕误导大家,所以粘出官方文档连接

https://docs.microsoft.com/zh-cn/ef/core/modeling/query-types

16:实体构造函数 (.net core 2.1 新增)

https://docs.microsoft.com/zh-cn/ef/core/modeling/constructors

17:固有实体类型(.net core 2.0 新增)

https://docs.microsoft.com/zh-cn/ef/core/modeling/owned-entities


总结

1:文章写到最后,还是没有全部坚持下来,比如说第15,16,17 没有写例子。其实我感觉他们都还挺重要。有时间了,我还会把这些内容补回来。

2:.net ef core 跟 .net ef 还是有很多差别的地方,有很多无法使用数据注解的方式解决,只能使用 fluent api。但是例如StringLength 注解,加上就是非空的。但是在fluent api 中没有发现这个。

3:欢迎大家指点错误和指导。


只有学习,内心才能踏实,我是CHIASING

.Net Core 之 Entity Framework Core -- Code Frist 数据注解及Fluent API_第6张图片

你可能感兴趣的:(.NET,Core)