一.主键

  键用作每个实体实例的主要唯一标识符。 使用关系数据库时,这会映射到主键的概念。 还可以配置不是主键的唯一标识符。按照约定,名为 Id 或 <type name>Id 的属性会配置为实体的键。例如下面二个示例:

class Car
{
//映射到Car表 Id主键
public string Id { get; set; }
}
class Car
{
//映射到Car表CarId主键,约定格式:<type name>Id
public string CarId { get; set; }
}

  除了上面讲到的约定,还可以用数据注释将单个属性配置为实体的键,下面示例使用数据注释配置主键

class Car
{
//映射到Car表LicensePlate主键
[Key]
public string LicensePlate { get; set; }
}

  还可以使用 Fluent API 将单个属性配置为实体的键。下面示例使用Fluent API配置主键

    class MyContext : DbContext
  {
   public DbSet<Car> Cars { get; set; }    protected override void OnModelCreating(ModelBuilder modelBuilder)
   {
  modelBuilder.Entity<Car>().HasKey(c => c.LicensePlate);
  }
  } class Car
{
public string LicensePlate { get; set; }
public string Make { get; set; }
public string Model { get; set; }
}

  还可以使用 Fluent API 将多个属性配置为实体的键(称为复合键)。 只能使用 Fluent API 配置复合键 - 不能使用约定来设置复合键,也不能使用数据注释来配置复合键。

class MyContext : DbContext
{
public DbSet<Car> Cars { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>()
.HasKey(c => new { c.State, c.LicensePlate });
}
}

二.生成的值

  对于属性的值生成模式有三种:(1) 无值生成;(2) 在新增时自动生成值;(3) 在添加或更新时自动生成值。下面介绍数据注释中使用DatabaseGeneratedOption枚举来实现,说明这三种生成模式的应用场景:

 public class Blog
{
//没有值生成, 主键一般在数据库中都是自增,所以在EF中不需要给值
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int BlogId { get; set; } //在新增时生成值, 一般插入一条数据时,记录插入的时间
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public DateTime Inserted { get; set; } //在新增或修改时生成值, 一般记录修改的时间。
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime LastUpdated { get; set; }
}

  除了用数据注释方法生成值,还可以使用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();

三. 最大长度

  最大长度仅适用于数组,数据类型,如 string 和 byte[]。将数据传递到提供程序之前,实体框架不会执行任何最大长度验证。 由提供程序或数据存储在适当时机进行验证。以 SQL Server 为目标,超过最大长度将引发异常。

  使用数据注释来配置属性的最大长度。 此示例面向 SQL Server,因此使用数据类型 nvarchar(500)。

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

  使用 Fluent API 配置属性的最大长度。 此示例面向 SQL Server,因此使用数据类型 nvarchar(500)

    modelBuilder.Entity<Blog>().Property(b => b.Url).HasMaxLength();

四.并发标记

  配置并发标记是用于解决数据库中的并发冲突。数据库并发:指多个进程或用户同时访问或更改数据库中的相同数据的情况。 并发控制:指的是用于在发生并发更改时确保数据一致性的特定机制。

  并发标记的实现是通过EF Core来实现并发冲突的解决,而非在数据库层面的方案。EF Core 实现了乐观并发控制(非数据库层面),这意味着它将允许多个进程或用户独立进行更改,而不会产生同步或锁定的开销。 在理想情况下,这些更改将不会相互干扰,因此都能够成功。 在最坏的情况下,两个或更多进程将尝试进行冲突更改,而其中只有一个进程会成功。

  4.1 并发控制在 EF Core 中的工作原理:

    配置为并发标记的属性用于实现乐观并发控制:每当在 SaveChanges 期间执行更新或删除操作时,会将数据库上的并发标记属性值与通过 EF Core 读取的原始值进行比较:

    (1) 如果这些值匹配,则可以完成该操作。

    (2) 如果这些值不匹配,EF Core 会假设另一个用户已执行冲突操作,并中止当前事务。这种情况被称为"并发冲突"。

    当配置好并发标记后,数据库提供程序负责实现并发标记值的比较,EF Core 会对任何 UPDATE 或 DELETE 语句的 WHERE 子句中的并发标记值进行检查。执行这些语句后,EF Core 会读取受影响的行数。如果未影响任何行,将检测到并发冲突,并且 EF Core 会引发 DbUpdateConcurrencyException。

    例如,将 Person 的 LastName 配置为并发标记。 这样,对 Person 的任何更新操作(并发标记的属性必须作为比较参照来反映并发冲突),都将在 WHERE 子句中做并发检查,在数据库端将执行如下sql命令,条件LastName 是EF自动加上去:

  UPDATE [Person] SET [FirstName] = @p1 WHERE [PersonId] = @p0 AND [LastName] = @p2;

    

    并发标记后会有三组值可用于帮助解决并发冲突:

      1.“当前值”是应用程序尝试写入数据库的值。
      2.“原始值”是在进行任何编辑之前最初从数据库中检索的值。
      3.“数据库值”是当前存储在数据库中的值。

    产生并发冲突的常规处理步骤是:
      1.在 SaveChanges 期间捕获 DbUpdateConcurrencyException。
      2.使用 DbUpdateConcurrencyException.Entries 为受影响的实体准备一组新更改。
      3.刷新并发标记的原始值以反映数据库中的当前值。
      4.重试该过程,直到不发生任何冲突。

  下面使用数据注释方法将LastName属性配置为并发标记

public class Person
{
public int PersonId { get; set; } [ConcurrencyCheck]
public string LastName { get; set; } public string FirstName { get; set; }
}

  下面使用Fluent API 可用于将LastName属性配置为并发标记

   modelBuilder.Entity<Person>().Property(p => p.LastName).IsConcurrencyToken();

  

  总结:并发冲突的产生,一般只有在生产环境或模拟大量用户线程的情况下才可能产生关系型数据库的并发死锁。产生死锁的原因有很多,如未建索引导致表扫描、或未按同一顺序访问对象等。只有分析出死锁的原因( sqlserver 死锁分析) (mysql死锁分析),才考虑结合EF的并发标记来解决。

  参考文献:

    官方资料: 主键

            生成的值

            最大长度

            并发标记

    

asp.net core系列 24 EF模型配置(主键,生成值,最大长度,并发标记)的更多相关文章

  1. asp.net core系列 28 EF模型配置(字段,构造函数,拥有实体类型)

    一. 支持字段 EF允许读取或写入字段而不是一个属性.在使用实体类时,用面向对象的封装来限制或增强应用程序代码对数据访问的语义时,这可能很有用.无法使用数据注释配置.除了约定,还可以使用Fluent ...

  2. asp.net core系列 29 EF模型配置(查询类型,关系数据库建模)

    一.查询类型 此功能是EF Core 2.1中的新功能. EF Core除了实体类型之外,EF Core模型还可以包含查询类型,这些查询类型是针对“未映射到实体类型”的数据获取.比如视图,或只读数据表 ...

  3. asp.net core系列 23 EF模型配置(概述, 类型和属性的包含与排除)

    一.模型配置概述 EF使用一组约定基于实体类的定义来构建模型. 可指定其他配置以补充或替代约定的内容.本系列介绍的配置可应用于面向任何数据存储的模型,以及面向任意关系数据库时可应用的配置. 数据库提供 ...

  4. asp.net core系列 27 EF模型配置(索引,备用键,继承)

    一.索引 索引是许多数据存储中的常见概念.虽然它们在数据存储中的实现可能会有所不同,但它们可用于更有效地基于列(或列集)进行查找.按照约定,用作外键每个属性 (或组的属性) 会自动创建索引.无法使用数 ...

  5. asp.net core系列 26 EF模型配置(实体关系)

    一.概述 EF实体关系定义了两个实体互相关联起来(主体实体和依赖实体的关系,对应数据库中主表和子表关系). 在关系型数据库中,这种表示是通过外键约束来体现.本篇主要讲一对多的关系.先了解下描述关系的术 ...

  6. asp.net core系列 25 EF模型配置(隐藏属性)

    一. 隐藏属性概述 隐藏属性也叫影子属性,该属性不是在.net实体类中定义的属性,而是在EFCore模型中为该实体类型定义的属性.这些属性的值和状态完全在变更跟踪器中维护.它有二个功能:(1)当数据库 ...

  7. asp.net core系列 30 EF管理数据库架构--必备知识 迁移

    一.管理数据库架构概述 EF Core 提供两种主要方法来保持 EF Core 模型和数据库架构同步.一是以 EF Core 模型为基准,二是以数据库为基准. (1)如果希望以 EF Core 模型为 ...

  8. asp.net core系列 31 EF管理数据库架构--必备知识 反向工程

    一.   反向工程 反向工程是基于数据库架构,生成的实体类和DbContext类代码的过程,对于Visual Studio开发,建议使用PMC.对于其他开发环境,请选择.NET Core CLI工具( ...

  9. 【目录】asp.net core系列篇

    随笔分类 - asp.net core系列篇 asp.net core系列 68 Filter管道过滤器 摘要: 一.概述 本篇详细了解一下asp.net core filters,filter叫&q ...

随机推荐

  1. E - Elevator

    E - Elevatorhttp://codeforces.com/gym/241680/problem/E同余最短路,从0~a-1中每一个i向(i+b)%a连一条权值为b的边,向(i+c)%a连一条 ...

  2. 让java代码在Idea外面运行起来

    今天在写聊天程序,终于写到双方通信的时候,发现idea只能开一个客户端.虽说可以开多线程来实现多开,但是懒得改动代码,所以我就试试能不能把jar包导出来运行.首先我用maven自带的工具打了jar包, ...

  3. 在github上面创建新的分支

    第一步:git branch 查看当前分支情况 git branch //查看当前分支情况 第二步:git branch 分支名,新建一个自己的分支 git branch 分支名 // 新建一个自己的 ...

  4. 心得体会,搞清楚你为什么学习C++?

    小编作为一名初学者时,从来没问过自己学习C语言.C++等语言是为了什么? 一开始,接触到这个行业可以说是有种魔力引导我,感到了很大的兴趣,很有意思. 我试着读资料,报名学习,找资料,可算是功夫不负有心 ...

  5. Tensor索引操作

    #Tensor索引操作 ''''' Tensor支持与numpy.ndarray类似的索引操作,语法上也类似 如无特殊说明,索引出来的结果与原tensor共享内存,即修改一个,另一个会跟着修改 ''' ...

  6. 编译部署 Mysql 5.7

    1.环境准备 RHEL7.4(最小化安装)  64bit   2G 内存 (1G 内存编译将近一个小时) 磁盘空间 15G 以上. 配置为本地yum 源 从MySQL5.7版本开始,安装MySQL需要 ...

  7. Ubuntu上安装使用WeChat、TIM

    WeChat可以直接到软件商店安装,不过是网页版...(其实个人感觉还行,就是什么都不能设置就挺蛋疼的,字体大小.背景什么的) 以下是网上找到的教程,在此总结一下: 下载地址:https://gith ...

  8. 常用的js效果

    使用jquery实现鼠标悬停显示层 <!DOCTYPE html> <html> <head> <meta charset="utf-8" ...

  9. 从url中获得域名

    import java.net.MalformedURLException; import java.net.URL; /** * * @author csh * */ public class AA ...

  10. 【ASP】response和sever对象实现用户登录

    1.问题提出 设计两个登录界面:一个register.asp页面用于输入账号,密码等信息进行登录.另一个页面welcome.asp用于显示登录成功的信息.利用request的两个对象response和 ...