.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<DataAnnotationsAttribute>(eb =>
        {
            eb.Property(b => b.Name).HasColumnType("varchar(50)");
            eb.Property(b => b.FullName).HasColumnType("varchar(60)");
        });
    }

 

 

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

3. 主键 [key]

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

Fluent API

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

数据库图:略

4. 复合主键

Fluent API

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

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

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

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Person>()
            .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<Order> Orders { get; set; }

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

        modelBuilder.Entity<Order>()
            .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<Blog> Blogs { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .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<Blog>().HasIndex(b => b.Url).IsUnique();
    // 非唯一
     modelBuilder.Entity<Blog>().HasIndex(b => new { b.RegistrationNumber1, b.RegistrationNumber2 });
}

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<Student> Students { get; set; }
}
// Fluent API
protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Student>()
            .HasOne<Grade>(s => s.Grade)
            .WithMany(g => g.Students)
            .HasForeignKey(s => s.CurrentGradeId);
    }

    public DbSet<Grade> Grades { get; set; }
    public DbSet<Student> Students { get; set; }

一对一:

// 实体
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<Student>()
            .HasOne<StudentAddress>(s => s.Address)
            .WithOne(ad => ad.Student)
            .HasForeignKey<StudentAddress>(ad => ad.AddressOfStudentId);
    }

    public DbSet<Student> Students { get; set; }
    public DbSet<StudentAddress> StudentAddresses { get; set; }

多对多:

// 实体
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<StudentCourse> StudentCourses { get; set; }
}

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

    public IList<StudentCourse> StudentCourses { get; set; }
}
// Fluent API

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

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


modelBuilder.Entity<StudentCourse>()
    .HasOne<Course>(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<BlogMetadata>();
    }
 排除属性
 protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .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<Blog>()
            .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<Blog>()
            .Property(p => p.Timestamp)
            .IsRowVersion();
     modelBuilder.Entity<Blog>().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<Rider>()
        .Property(e => e.Mount)
        .HasConversion(
            v => v.ToString(),
            v => (EquineBeast)Enum.Parse(typeof(EquineBeast), v));
    // DATA SEEDING
    modelBuilder.Entity<Blog>().HasData(new Blog { BlogId = 1, Url = "http://sample.com" });

}

数据迁移后的结果是:

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

BoolToZeroOneConverter将布尔值转换为0或1
BoolToStringConverter将布尔值转换为字符串(Y或N)
BoolToTwoValuesConverter将布尔值转换为指定的两个值(没搞明白干嘛用的)
BytesToStringConverter将字节数组转换为Base64编码的字符串
CastingConverter从一种类型转换到另一种类型(可以被C#互相转换的类型)
CharToStringConverterchar转为string
DateTimeOffsetToBinaryConverterDateTimeOffset转为二进制的64位的值
DateTimeOffsetToBytesConverterDateTimeOffset转为字节数组
DateTimeOffsetToStringConverterDateTimeOffset转为字符串
DateTimeToBinaryConverterDateTime转为带有DateTimeKind的64位的值
DateTimeToStringConverterDateTime转为字符串
DateTimeToTicksConverterDateTime转为ticks
EnumToNumberConverter枚举转数字
EnumToStringConverter枚举转字符串
GuidToBytesConverterGuid转字节数组
GuidToStringConverterGuid转字符串
NumberToBytesConverter数字转字节数组
NumberToStringConverter数字转字符串
StringToBytesConverter字符串转字节数组
TimeSpanToStringConverterTimeSpan转字符串
TimeSpanToTicksConverterTimeSpan转ticks

 

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

var converter = new EnumToStringConverter<Person>();
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

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chiasing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值