当前位置: 首页 > 编程日记 > 正文

Entity Framework 约定

约定,类似于接口,是一个规范和规则,使用Code First 定义约定来配置模型和规则。在这里约定只是记本规则,我们可以通过Data Annotaion或者Fluent API来进一步配置模型。约定的形式有如下几种:

  • 类型发现约定
  • 主键约定
  • 关系约定
  • 复杂类型约定
  • 自定义约定

零、类型发现约定

在Code First 中。我们定义完模型,还需要让EF上下文你知道应该映射那些模型,此时我们需要通过 DbSet 属性来暴露模型的。如果我们定义的模型由继承层次,只需要为基类定义一个DbSet属性即可(如果派生类与基类在同一个程序集,派生类将会被自动包含),代码如下:

public class Department
{public int DepartmentId { get; set; }public string Name { get; set; }public virtual ICollection<Blog> Blogs { get; set; }
}public class EfDbContext : DbContext
{public EfDbContext(){}public DbSet<Department> Departments { get; set; }
}复制代码

当然,有时候我们不希望模型映射到数据库中,这时我们可以通过Fluent API 来忽略指定的模型映射到数据库中,代码写在EF上下文中:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{modelBuilder.Ignore<Department>();
}
复制代码

一、主键约定

Code First 会根据模型中定义的***id***,推断属性为主键(如果类中没有id属性,会查找定义成***类名称+id***的属性,将这个属性作为主键)。如果主键类型是***int*** 或者 guid 类型,主键将会被映射为自增长标识列。例如我们上一小节中定义的类 Department,类中没有名称为id的属性,但是存在名称为类名称+id的属性***DepartmentId***,因此DepartmentId属性,将会被映射为自增长的主键。如果一个类中既没有id属性,也没有类名+id的属性,那么代码在运行时将会报错,因为EF没有找到符合要求的字段创建主键。

二、关系约定

在数据库中,我们可以通过多张表的关联查询出数据,这多张表之间的关联,就是他们的关系。同样,也可以在模型中定义这样的关系。EF中定义关系要使用到导航属性,通过导航属性可以定义多个模型之间的关系。大部分情况下我们会将导航属性和外键属性结合在一起使用。导航属性的命名规则如下:导航属性名称+主体主键名称 或者 主体类名+主键属性名称 或者 主体主键属性名。当EF检测出外键属性后,会根据外键属性是否为空来判断关系,如果外键可以为空,那么模型之间的关系将会配置成可选的,Code First 不会再关系上配置级联删除。看一个简单的代码:

public class Department
{public int DepartmentId { get; set; }public string Name { get; set; }public virtual ICollection<Student> Students { get; set; }
}public class Student
{public int StudentId { get; set; }public string Name { get; set; }public int DepartmentId { get; set; }public virtual Department Department { get; set; }
}
复制代码

三、复杂类型约定

在Code First 不能推断出模型中的主键,并且没有通过Data Annotations 或者Fluent API进行手动配置主键时,该模型将会自动被配置为复杂类型,检测复杂类型时要求该类型没有引用实体类型的属性。简单的说就是:一个复杂类型作为已存在对象的属性,EF会将复杂类型的类映射到已存在的表中,已存在的表包将包含这些列,而不是将复杂类型映射成另外单独的一张表。我们来看一下例子:

public class EfDbContext : DbContext
{protected override void OnModelCreating(DbModelBuilder modelBuilder){modelBuilder.Entity<Order>().ToTable("Orders");modelBuilder.ComplexType<Order.Address>();}public DbSet<Order> Orders { get; set; }
}public class Order
{public int Id;public string Name;public class Address{public string Street;public string Region;public string Country;}
}复制代码

四、自定义约定

当EF提供的默认约定都不符合我们要求的时候,我们可以使用自定义约定。自定义约定可以看作全局约定规则,将会运用到所有实体和属性,也可以显示实现应用到指定的模型上。

如果项目要求模型中有Id属性,就将Id作为主键映射,那么我们有两种选择来定义这个约定,首先我们而已选择Fluent API ,其次我们也可以选择自定义约定。自定义约定相对来说比Fluent API 要简单,只需一行代码即可解决。我们只需要在 OnModelCreating 方法中加入如下代码即可:

modelBuilder.Properties().Where(p => p.Name == "Id").Configure(p => p.IsKey());
复制代码

注:当多个属性存在相同约定配置时,最后一个约定将覆盖前面所有相同的约定。

自定义约定包含一个约定接口 IConvention,IConceptualModelConvention 是概念模型接口,在模型创建后被调用,IStoreModelConvention 接口为存储模型接口,在模型创建之后用于操作对模型的存储,***自定义类约定***都必须在 OnModelCreating 方法中显式配置,例如我们要将模型中类型为DateTime的属性映射为datetime2,可进行如下配置:

public class DateTime2Convention : Convention
{public DateTime2Convention(){this.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));}
}protected override void OnModelCreating(DbModelBuilder modelBuilder)
{modelBuilder.Conventions.Add(new DateTime2Convention());
}复制代码

当我们自定义约定需要在另一个约定运行之前或者运行之后执行时,有可能会受到默认原定的影响,这时我们可以用到:*AddBeforeAddAfter 方法,例如:将我们前面创建的约定放在内置约定发现逐渐约定之前运行。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{modelBuilder.Conventions.AddBefore<IdKeyDiscoveryConvention>(new DateTime2Convention());
}
复制代码

在开发过程中都会存在开发规范,例如对表名命名的规则,我们可以调用Types 方法该表表明约定,代码如下:

public string GetTableName(Type type)
{var result = Regex.Replace(type.Name, ".[A-Z]",m=>m.Value[0]+"_"+m.Value[1]);return result.ToLower();
}protected override void OnModelCreating(DbModelBuilder modelBuilder)
{modelBuilder.Types().Configure(c => c.ToTable(GetTableName(c.ClrType)));
}
复制代码

上述我们讲的都是针对全局的约定,我们在开发工程中大部分遇到的是针对符合特定条件的模型进行约定,此时我们就用到了自定义特性。我们先来看一段代码:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class NoUnicode : Attribute
{
}
复制代码

这段代码将类型为字符串的属性配置为非Unicode,下面我们建上面的特性应用到所有模型

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{modelBuilder.Properties().Where(x => x.GetCustomAttributes(false).OfType<NoUnicode>().Any()).Configure(c => c.IsUnicode(false));
}
复制代码

添加该特性后,映射在数据库中的列将是 varchar 类型,而不是 nvarchar 类型。但是上述代码存在一个问题,如果匹配的不是字符串类型将会报错,因此我们将代码更新如下:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{modelBuilder.Properties().Where(c => c.GetCustomAttributes(false).OfType<NoUnicode>().Any()).Configure(c => c.IsUnicode(false));modelBuilder.Properties().Having(x => x.GetCustomAttributes(false).OfType<IsUnicode>().FirstOrDefault()).Configure((config, attr) => config.IsUnicode(attr.Uniconde));
}[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class NoUnicode : Attribute
{
}[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
internal class IsUnicode : Attribute
{public bool Uniconde { get; set; }public IsUnicode(bool isUnicode){Uniconde = isUnicode;}
}
复制代码

转载于:https://juejin.im/post/5d01b808f265da1bcd37d1cc

相关文章:

java用构造方法定义book类_JAVA基础学习之路(三)类定义及构造方法

类的定义及使用一&#xff0c;类的定义classBook {//定义一个类intprice;//定义一个属性intnum;public static int getMonney(int price, intnum) {//定义一个方法return price*num;}}public classtest2 {public static voidmain(String args[]) {Book monney newBook();//声明…

Linux下如何查看文档的内容

查看文档内容的命令有&#xff1a;cat tac head nl tail more less odcat命令显示文档的全部内容&#xff0c;当文档较大的时候只显示最后的部分&#xff0c;所以cat命令适合查看内容较少的文档。可加选项-n显示行数(此时空白行也会显示行号)。-b空白行则不显示行号。tac与cat显…

Java中getResourceAsStream的用法

Java中getResourceAsStream的用法 首先&#xff0c;Java中的getResourceAsStream有以下几种&#xff1a;1. Class.getResourceAsStream(String path) &#xff1a; path 不以’/开头时默认是从此类所在的包下取资源&#xff0c;以’/开头则是从 ClassPath根下获取。其只是通过p…

Asp.Net MVC3 简单入门详解过滤器Filter

为什么80%的码农都做不了架构师&#xff1f;>>> 前言 在开发大项目的时候总会有相关的AOP面向切面编程的组件&#xff0c;而MVC&#xff08;特指&#xff1a;Asp.Net MVC&#xff0c;以下皆同&#xff09;项目中不想让MVC开发人员去关心和写类似身份验证&#xff0…

mysql 锁语句_mysql-笔记 事务 锁 语句

Start Transaction 或 begin [work] 开始一个事务&#xff0c;开始一个事务&#xff0c;引起其他未提交的事务提交&#xff0c;引起表锁释放commit 提交事务&#xff0c;永久修改rollback 回滚事务&#xff0c;撤消修改set autocommit 在当前会话状态下 启用或不启用 autocommi…

【收藏】Java多线程/并发编程大合集

&#xff08;一&#xff09;、【Java并发编程】并发编程大合集-兰亭风雨 【Java并发编程】实现多线程的两种方法 【Java并发编程】线程的中断 【Java并发编程】正确挂起、恢复、终止线程 【Java并发编程】守护线程和线程阻塞 【Java并发编程】Volatile关键字&#xff08;上&…

《深入理解Android:Wi-Fi,NFC和GPS》章节连载[节选]--第六章 深入理解wi-Fi Simple Configuration...

为什么80%的码农都做不了架构师&#xff1f;>>> 首先感谢各位兄弟姐妹们的耐心等待。本书预计在4月上市发售。从今天开始&#xff0c;我将在博客中连载此书的一些内容。注意&#xff0c;此处连载的是未经出版社编辑的原始稿件&#xff0c;所以样子会有些非专业。 …

iOS 的本地化使用和创建过程

在使用本地化语言之前&#xff0c;来看看本地化语言文件内容的结构&#xff08;这里我以Chinese为例&#xff09;&#xff1a;"Cancel""取消";"OK""确定";"Tip""信息提示";"Login Faild""登陆失败…

MySQL中改变相邻学生座位_力扣——换座位(数据库的题

小美是一所中学的信息科技老师&#xff0c;她有一张 seat 座位表&#xff0c;平时用来储存学生名字和与他们相对应的座位 id。其中纵列的 id 是连续递增的小美想改变相邻俩学生的座位。你能不能帮她写一个 SQL query 来输出小美想要的结果呢&#xff1f;示例&#xff1a;------…

AnsiToUtf8 和 Utf8ToAnsi

在服务端数据库的处理当中&#xff0c;涉及中文字符的结构体字段&#xff0c;需要转为Utf8后再存储到表项中。从数据库中取出包含中文字符的字段后&#xff0c;如果需要保存到char *类型的结构体成员中&#xff0c;需要转为Ansi后再保存。从数据库中取出类型数字的字段后&#…

常见面试题:重写strcpy() 函数原型

已知strcpy函数的原型是 char* strcpy(char* strDest,const char* strSrc); 1.不调用库函数&#xff0c;实现strcpy函数 2.解释为什么要返回char*; 1.strcpy的实现代码 char* strcpy(char* strDest,const char* strSrc) { if((strDest NULL) || (strSrc NULL)) //[1] thro…

mongodb 系列 ~ journal日志畅谈

一 简介 我们来聊聊Journal日志二 核心观点 WAL 日志先行策略三 开启journal流程 在开启journal的系统中&#xff0c;写操作从请求到写入磁盘共经历5个步骤&#xff0c;在serverStatus()中已经列出各个步骤消耗的时间。 1 Write to privateView 2 prepLogBuffer …

java striptrailingzeros_java – 为什么不BigDecimal.stripTrailingZeros()总是删除所有尾随零?...

我做了以下事情MathContext context new MathContext(7, RoundingMode.HALF_UP);BigDecimal roundedValue new BigDecimal(value, context);// Limit decimal placestry {roundedValue roundedValue.setScale(decimalPlaces, RoundingMode.HALF_UP);} catch (NegativeArrayS…

box-shadow属性

一、定义和用法 box-shadow属性 向框添加一个或多个阴影。 二、语法 box-shadow: h-shadow v-shadow blur spread color inset; h-shadow必需。水平阴影的位置。允许负值。 v-shadow必需。垂直阴影的位置。允许负值。 blur可选。模糊距离。 spread可选。阴影的尺寸。 color可选…

秋色园QBlog技术原理解析:性能优化篇:用户和文章计数器方案(十七)

2019独角兽企业重金招聘Python工程师标准>>> 上节概要&#xff1a; 上节 秋色园QBlog技术原理解析&#xff1a;性能优化篇&#xff1a;access的并发极限及分库分散并发方案(十六) 中&#xff0c; 介绍了 Access的并发上限&#xff0c;及从某种程度上 秋色园QBlog 针…

ldconfig

为了让动态链接库为系统所共享,还需运行动态链接库的管理命令--ldconfigldconfig 命令的用途,主要是在默认搜寻目录(/lib和/usr/lib)以及动态库配置文件/etc/ld.so.conf内所列的目录下,搜索出可共享的动态 链接库(格式如前介绍,lib*.so*),进而创建出动态装入程序(ld.so)所需的连…

MySQL宽字节注入漏洞分析_宽字节注入

概念单字节字符集&#xff1a; 所有的字符都使用一个字节来表示&#xff0c;比如 ASCII 编码。多字节字符集&#xff1a; 在多字节字符集中&#xff0c;一部分字节用多个字节来表示&#xff0c;另一部分(可能没有)用单个字节来表示。两位的多字节字符有一个前导字节和尾字节。 …

objc runtime 动态增加属性

objective-c中&#xff0c;有类别可以在不修改源码的基础上增加方法 使用运行时库&#xff0c;必须要先引入 objc/runtime.h 可以使用的函数如下&#xff1a; OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy…

C#合并两张表结构相同(列数和列类型都相同)的表

DataTable appendDataTablenew DataTable(); 这个合并的大前提是两张表的结构相同且列的类型也必须相同 否则在赋值时就会出现异常。 for (int i 0; i < hostDt.Columns.Count;i ) { appendDataTable.Columns.Add(hostDt.Columns[i].ColumnName,hostDt.Columns[i].DataType…

erlang调优方法

2019独角兽企业重金招聘Python工程师标准>>> 1. 来自Scaling Erlang的方法 内核调优&#xff1a; # Increase the ipv4 port range: sysctl -w net.ipv4.ip_local_port_range"1024 65535" # General gigabit tuning: sysctl -w net.core.rmem_max16777…

mysql第四章_MySQL必知必会--第二章~第四章--MySQL简介

1.DBMS可分为两类:一类为基于共享文件系统的DBMS&#xff0c;另一类为基于客户机—服务器的DBMS。服务器部分是 负责所有数据访问和处理的一个软件。这个软件运行在称为数据库服务 器的计算机上。2.MySQL Administrator(MySQL管理器)是一个图形交互客户机&#xff0c;用 来简化…

Windows Phone 7编程学习点滴一——页面切换、返回键重载和工具栏

1. 页面切换和对齐方式 2 &#xff08;1&#xff09;XAML实现方式 <HyperlinkButton Content"TestPage1" NavigateUri"/TestPage1.xaml" Height"30" HorizontalAlignment"Left" Margin"10,10,0,0" Name"TestPage1Li…

call_user_func用法

1 //有一些函数&#xff0c;名字未知2 //名字在运行状态时&#xff0c;才知道3 4 //例如a(),b(),c()调用哪一个5 // ->index(),reg()?又调用哪一个6 7 function t(){8 echo hello;9 } 10 11 function s(){ 12 echo world; 13 } 14 15 $at; 16 //$a(); 17 18 //在…

构建现代化的命令行工具

文章源于 lambdas.dev 每当我们想要创建一个基于 NodeJS 的命令行工具时&#xff0c;就会衍生出一堆问题需要解决&#xff0c;比如如何准备开发环境&#xff0c;如何打包转译代码&#xff0c;如何使代码在转译后保持可调用的状态同时尽可能的压缩体积&#xff0c; 以及怎样设计…

Java怎么定义图片公共路径_【Java】springboot配置图片访问路径

springboot如何配置&#xff0c;就可以在地址栏输入http://localhost:9090/17AD93E86EB44287BA0D871A37017597.jpg就可以访问到图片回答需要添加下Springboot访问静态资源的Jar文件org.springframework.bootspring-boot-starter-thymeleaf直接去掉这两个配置就行&#xff0c;自…

PHP——文件操作

自己写的&#xff1a; <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns"http://www.w3.org/1999/xhtml"> <head> <meta http-e…

linux基础—课堂随笔010_系统启动和内核管理

系统启动和内核管理 Linux: kernelrootfs kernel: 进程管理、内存管理、网络管理、驱动程序、文件系统、安全功能 rootfs:程序和glibc 库&#xff1a;函数集合, function, 调用接口&#xff08;头文件负责描述&#xff09; 程序&#xff1a;二进制执行文件 内核设计流派&…

微软技术的变迁

这个课题很大&#xff0c;我只是站在一个普通人的视角上写一下。 微软的看家技术是什么&#xff1f;vb&#xff01;先有basic&#xff0c;再有操作系统&#xff0c;dos发展到windows&#xff0c;vb一直发展着。然而到达vb6之后&#xff0c;微软转型设计.net 。.net 是什么&…

java initcause_Java 异常

问&#xff1a;java 异常有哪几种&#xff0c;特点是什么&#xff1f;答&#xff1a;异常是发生在程序执行过程中阻碍程序正常执行的错误操作&#xff0c;只要在 Java 语句执行中产生异常&#xff0c;则一个异常对象就会被创建。Throwable 是所有异常的父类&#xff0c;它有两个…

UICollectionView之网络图片解析

1&#xff1a;将SDWebImage文件夹的类库导入工程&#xff0c;创建一个模型对象Model类&#xff0c;并声明好它的属性&#xff0c;再创建一个继承自UICollectionViewCell的自定义类 2&#xff1a;在自定义cell类中重写 - (instancetype)initWithFrame:(CGRect)frame { self [su…