最新版本号[免费下载]

EntityFramework Core 学习扫盲 (中)

作者:本站编辑 发布时间:2018-09-30 来源:佚名 点击数:

6. 备用键

Alternate Keys是EF CORE引入的新功能,EF 6.X版本中并没有此功能。备用键可以用作实体中除主键和索引外的唯一标识符,还可以用作外键目标。在Fluent Api中,有两种方法可以指定备用键,一种是当开发者将实体中的属性作为另一个实体的外键目标,另一种是手动指定。EF CORE的默认约束是前者。

备用键和主键的作用十分相似,同样也存在复合备用键的功能,请大家注意区分。在要求单表列的一致性的场景中,使用唯一索引比使用备用键更佳。

1. Fluent API

public class MyContext : DbContext{    public MyContext(DbContextOptions<MyContext> options) : base(options)    {
    }    public DbSet<Car> Cars { get; set; }    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.BlogUrl)
            .HasPrincipalKey(b => b.Url);            
        // 第二种方法
        modelBuilder.Entity<Car>()
            .HasAlternateKey(c => c.LicensePlate)
            .HasName("AlternateKey_LicensePlate");
    }
}public class Car{    public int CarId { get; set; }    public string LicensePlate { get; set; }    public string Make { get; set; }    public string Model { get; set; }
}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 string BlogUrl { get; set; }    public Blog Blog { get; set; }
}

上述代码中的第一种方法指定Post实体中的BlogUrl属性作为Blog对应Post的外键,指定Blog实体中的Url属性作为备用键(HasPrincipalKey方法将在下文的唯一标识节中讲解),此时Url将被配置为唯一列,扮演BlogId的作用。

7. 计算列

计算列指的是列的数据由数据库计算生成,在EF CORE层面,我们只需要定义计算规则即可。目前EF CORE 1.1 版本中,暂不支持使用Data Annotations方式定义。

1 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; }
}

以上代码指明DisplayName由LastName和FirstName结合计算而成,这项工作由数据库代劳,查看P的视图设计器,我们也可以发现数据库在生成表时便指定了详细规则。

CREATE TABLE [dbo].[People] (
    [PersonId]    INT            IDENTITY (1, 1) NOT NULL,
    [DisplayName] AS             (([LastName]+', ')+[FirstName]),
    [FirstName]   NVARCHAR (MAX) NULL,
    [LastName]    NVARCHAR (MAX) NULL,    CONSTRAINT [PK_People] PRIMARY KEY CLUSTERED ([PersonId] ASC)
);

8. 生成值

前文中已经介绍过,假如属性被命名为Id/[TypeName]Id的形式,EF CORE会将该属性设置为主键。进一步说,如果属性是整数或是Guid类型,那么该属性将会被EF CORE设置为自动生成。这是EF CORE的语法糖之一。

那由用户手动设置呢?EF CORE在Data Annotations和Fluent Api形式上为开发者分别提供了三种方法。

1 Data Annotations

  • 不生成(默认方式)

public class Blog{
    [DatabaseGenerated(DatabaseGeneratedOption.None)]    public int BlogId { get; set; }    public string Url { get; set; }
}
  • 新增实体信息时自动添加

public class Blog{    public int BlogId { get; set; }    public string Url { get; set; }
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]    public DateTime Inserted { get; set; }
}
  • 新增或更新实体时自动添加

public class Blog{    public int BlogId { get; set; }    public string Url { get; set; }
    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]    public DateTime LastUpdated { get; set; }
}

2 Fluent API

  • 不生成(默认方式)

modelBuilder.Entity<Blog>()
    .Property(b => b.BlogId)
    .ValueGeneratedNever();
  • 新增实体信息时自动添加

modelBuilder.Entity<Blog>()
    .Property(b => b.Inserted)
    .ValueGeneratedOnAdd();
  • 新增或更新实体时自动添加

modelBuilder.Entity<Blog>()
    .Property(b => b.LastUpdated)
    .ValueGeneratedOnAddOrUpdate();

值得注意的是,上述对DateTime类型的自动添加操作都是不可行的,这是因为EF CORE只支持部分类型的自动操作,详见Default Values。对于DateTime类型,我们可以用以下代码实现自动插入
modelBuilder.Entity<Blog>().Property(b => b.Created).HasDefaultValueSql("getdate()");
这也是第7点默认值的一种用法。

9. 默认值

默认值与计算列定义十分相似,只是计算列无法由用户手动输入。而默认值更多指的是当用户不手动输入时,使用默认值进行数据库相应列的填充。以下代码表示假如操作中不指定Rating的值,那么数据库将默认填充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; }
}

10. 索引

EF CORE中的索引概念和关系型数据库中的索引概念没有什么不同,比如在Sql Server,将Blog映射到数据库时,将为BlogId建立主键默认持有的聚集索引,将Post映射到数据库中时,将为Post的BlogId建议外键默认的非聚集索引。

GOCREATE NONCLUSTERED INDEX [IX_Posts_BlogId]    ON [dbo].[Posts]([BlogId] ASC);

至于为一个或多个属性手动建立索引,可以使用形如以下代码。

1. Fluent API

class MyContext : DbContext{    public DbSet<Blog> Blogs { get; set; }    public DbSet<Person> People { get; set; }    protected override void OnModelCreating(ModelBuilder modelBuilder)    {
        modelBuilder.Entity<Blog>()
            .HasIndex(b => b.Url)
            .HasName("IX_Url");
        
        modelBuilder.Entity<Person>()
            .HasIndex(p => new { p.FirstName, p.LastName });
    }
}public class Blog{    public int BlogId { get; set; }    public string Url { get; set; }
}public class Person{    public int PersonId { get; set; }    public string FirstName { get; set; }    public string LastName { get; set; }
}

假如你需要配置一个唯一索引,请使用IsUnique方法。形如以下代码:

modelBuilder.Entity<Blog>()
            .HasIndex(b => b.Url)
            .HasName("IX_Url")
            .IsUnique();


本文责任编辑: 加入会员收藏夹 点此参与评论>>
复制本网址-发给QQ/微信上的朋友
AI智能听书
选取音色