EF 学习系列二 数据库表的创建和表关系配置(Fluent API、Data Annotations、约定)

上一篇写了《Entity Farmework领域建模方式 3种编程方式》现在就Code First 继续学习

1、数据库表的创建

新建一个MVC的项目,在引用右击管理NuGet程序包,点击浏览搜索EF安装,我这里主要是EF6.0 以上的学习 所以都安装6.0 以上的版本

接下来在Model文件夹下面创建一个Customer类

 public class Customer
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public string Email { get; set; }
        public DateTime AddTime { get; set; }
    }

在创建一个继承EF上下文的类XXDBContext,(个人习惯XX是我的名字拼音缩写)此上下文是数据库交互的一个中间桥梁,我们称之为会话,并且为为一个模型公开一个DbSet。默认情况下EF链接LocalDB本地数据库(需要安装LocalDB实例),我还是手动通过EF上下文派生类的构造函数来配置数据库链接。下面我注释的是数据库初始化策略。我这里就选择始终创建数据库,后面用到配置表关联与字段的配置。

public class WYDBContext:DbContext
    {
        public WYDBContext(string ConnectionName) : base(ConnectionName) { }
        public WYDBContext():base("SqlConn")
        {
            //默认的初始化器。这种初始化器在第一次运行程序时会创建数据库,再次运行不会再创建新的数据库。但是如果我们改变了领域类,运行程序时会抛出一个异常
            //Database.SetInitializer(new CreateDatabaseIfNotExists<WYDBContext>());

            //如果领域类发生了改变,删除以前的数据库,然后重建一个新的。采用这种初始化器不用再担心领域类改变影响数据库架构的问题。
            //Database.SetInitializer(new DropCreateDatabaseIfModelChanges<WYDBContext.cs>());

            //每次运行程序都会删除以前的数据库,重建新的数据库。如果在开发过程中每次都想使用最新的数据库,那么可以采用这种初始化器。
            Database.SetInitializer(new DropCreateDatabaseAlways<WYDBContext>());

            //禁用数据库初始化策略
            //Database.SetInitializer<WYDBContext>(null);
        }
        public DbSet<Customer> Customer { get; set; }
    }

webconfig配置

<system.web>
    <compilation debug="true" targetFramework="4.6.1" />
    <httpRuntime targetFramework="4.6.1" />
  </system.web>

  <!--数据库连接-->
  <connectionStrings>
    <!--数据库连接ef字符串-->
    <add name="SqlConn" connectionString="Data Source=地址;Initial Catalog=数据库名;Persist Security Info=True;User ID=用户名;Password=密码;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
  </connectionStrings>

现在如果直接启动项目数据库是不会被创建的,只有调用到才会创建,在Home控制器的Index中调用,启动就生成了数据库

public ActionResult Index()
        {
            using (var db =new  WYDBContext())
            {
                db.Customer.ToList();
            }
            return View();
        }

2、 三者约定之 Code First约定(三者优先级 Fluent API > Data Annotations > 约定)

上面可已看出表Customer自己生成了主键ID。所谓约定,类似于C#中的接口,它是一个规范或者规则。使用Code First基于类定义通过约定来配置概念模型并以此为规则,约定就是基本规则。

Code First根据模型中定义的ID(不区分大小写),或者是以类名加ID的属性推断这样的属性为ID,如果为int或者guid类型,那么主键映射成标识列(自增长)。

Model下面在创建一个订单Order类一个客户有多个订单一个订单只能属于某一个客户这样客户与订单的关系就是一对多

 public class Order
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
        public string Remark { get; set; }
        public int CustomerID { get; set; }
        /// <summary>
        /// 订单对应的客户信息
        /// </summary>
        public virtual Customer Customer { get; set; }
    }

 public class Customer
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public string Email { get; set; }
        public DateTime AddTime { get; set; }
        /// <summary>
        /// 客户对应的订单信息
        /// </summary>
        public virtual IList<Order> Order { get; set; }
    }

数据库上下文WYDBContext加上 public DbSet<Order> Order { get; set; } 刚刚加的订单类,运行起来 如果数据库删除不了的 自己闪一下 (在navicat 里面使用会这样,我就换在SSMS里面用)

它也生成了表与表的对应关系,然而string类型的你会发现字段都是max这肯定不行。接下来看Data Annatations 配置

3、三者约定之 Data Annotations

Data Annotations我的理解就是在字段类名上面加特性注解来控制字段属性的 栗子如下  还是Order与Customer两张表 记得添加命名空间using System.ComponentModel.DataAnnotations;跟using System.ComponentModel.DataAnnotations.Schema;

public class Customer
    {
        /// <summary>
        /// ID
        /// </summary>
        [Key]//标识次列为主键
        [Column("Zj", Order = 0, TypeName = "int")]//列名Zj,数据库序号0,类型int
        [Required()]//不允许为空
        [Display(Name = "Zj")]//显示名称,这里大多都是中文 后面视图@Html.DisplayNameFor(item=> model.Name)用到 显示的
        public int Zj { get; set; }
        /// <summary>
        /// 姓名
        /// </summary>
        [Column("NameWYY", TypeName = "nvarchar")]//我加了WYY看效果
        [StringLength(50, ErrorMessage = "{0}长度不能超过50个字符")]
        [Display(Name = "姓名")]
        public string Name { get; set; }
        /// <summary>
        /// 年龄
        /// </summary>

        [Column("Age", TypeName = "int")]
        [Display(Name = "年龄")]
        public int? Age { get; set; }//加了?允许为null
        /// <summary>
        /// 邮箱
        /// </summary>
        [Column("Email", TypeName = "nvarchar")]
        [StringLength(50, ErrorMessage = "{0}长度不能超过50个字符")]
        [Display(Name = "电子邮箱")]
        public string Email { get; set; }
        /// <summary>
        /// 日期
        /// </summary>
        [Column("AddTime", TypeName = "datetime2")]//如果不定义datetime2添加DateTime.Now就会报错哦
        [Display(Name = "添加日期")]
        [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")]//日期格式化
        public DateTime AddTime { get; set; }
        /// <summary>
        /// 客户对应的订单信息
        /// </summary>
        public virtual IList<Order> Order { get; set; }
    }

// [NotMapped]//表不映射到数据库
    [Table("Tb_Order")]//表名
    public class Order
    {
        /// <summary>
        /// ID
        /// </summary>
        [Key]
        [Column("ID", Order = 0, TypeName = "int")]
        [Required()]
        [Display(Name = "ID")]
        public int ID { get; set; }
        /// <summary>
        /// 名称
        /// </summary>
        [Column("Name", TypeName = "nvarchar")]
        [StringLength(50, ErrorMessage = "{0}长度不能超过50个字符")]
        [Display(Name = "名称")]
        public string Name { get; set; }
        /// <summary>
        /// 价格
        /// </summary>
        [Column("Price")]
        [Display(Name = "价格")]
        public decimal? Price { get; set; }
        /// <summary>
        /// 备注
        /// </summary>
        [StringLength(3000)]//长度约束
        [Column("Remark", TypeName = "nvarchar")]//我加了WYY看效果
        [Display(Name = "备注")]
        public string Remark { get; set; }
        /// <summary>
        /// 客户ID
        /// </summary>
        [ForeignKey("Customer")]//外键
        public int CustomerID { get; set; }
        /// <summary>
        /// 订单对应的客户信息
        /// </summary>
        [ForeignKey("CustomerID")]//外键
        public virtual Customer Customer { get; set; }

        /// <summary>
        /// 不映射字段
        /// </summary>
        [NotMapped]//不映射到数据库
        public string XXX { get; set; }
    }

4、三者约定之 Fluent API

这个就要在派生类重写OnModelCreating了  少一点 的表还可以在里面设置各个字段多了还是映射Map在模型表里面写,在OnModelCreatiing注册模型类就可以了;

 public DbSet<Customer> Customer { get; set; }
        public DbSet<Order> Order { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            //TODO 配置映射
            modelBuilder.Entity<Customer>().ToTable("CSTo");//数据库表名
            modelBuilder.Entity<Customer>().HasKey(x => x.Zj);//主键
            modelBuilder.Entity<Customer>().Property(x=>x.AddTime).HasColumnType("DATETIME2");//时间
            modelBuilder.Entity<Customer>().Property(x=>x.Age).IsOptional();//为null
            //HasColumnType("DATETIME2(7)")这种写是错的
            modelBuilder.Entity<Customer>().Property(x => x.Name).IsRequired().HasColumnType("varchar").HasMaxLength(66);//不为空,类型,长度

            //默认情况下不会生成复数的表  如Orders
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
            modelBuilder.Configurations.Add(new OrderMap());//注册
            base.OnModelCreating(modelBuilder);

        }

// [NotMapped]//表不映射到数据库
    [Table("Tb_Order")]//表名
    public class Order
    {
        ///字段

    }
    public class OrderMap : EntityTypeConfiguration<Order>
    {
        public OrderMap()
        {
            //对应数据库表名
            this.ToTable("ORd");
            //一个订单必须对应有一个客户,客户一对多(订单)   用户表里面的 CustomerID
            this.HasRequired(p => p.Customer).WithMany(p => p.Order).HasForeignKey(p => p.CustomerID);
            this.HasKey(k => k.ID);//主键
            this.Property(p => p.Name).HasColumnType("VARCHAR").HasMaxLength(50).IsRequired();//Name字段属性(varchar,长度50,不为null)
            this.Property(p => p.Remark).HasColumnType("VARCHAR").HasMaxLength(5000).IsOptional();//Remark(varchar,长度5000,null)
            this.Property(p => p.Price).HasColumnName("pp");//列名
        }
    }

C#的数值类型对应数据库如下

●C#中的 int类型默认映射后对应数据库中的int类型。

● C#中的double类型默认映射后对应数据库中的float类型

●C#中的float类型默认映射后对应数据库中的real类型。

●C#中 的decimal类型默认映射后对应数据库中的decimal(18,2)类型

●C#中 的Int64类型默认映射后对应数据库中的bigint类型。

一般都是用Data Anntations  跟默认的约定好久没用记录一下  用到又来拿  Fluent API也是好久没复习了 哈哈 有时间在看看书

原文地址:https://www.cnblogs.com/w5942066/p/12160781.html

时间: 2024-10-10 03:28:10

EF 学习系列二 数据库表的创建和表关系配置(Fluent API、Data Annotations、约定)的相关文章

windows下mongodb基础玩法系列二CURD操作(创建、更新、读取和删除)

windows下mongodb基础玩法系列 windows下mongodb基础玩法系列一介绍与安装 windows下mongodb基础玩法系列二CURD操作(创建.更新.读取和删除) 简单说几句 在mongodb中3元素:db(数据库).collection(集合).document(文档) 其中collection类似于数据库中的表,document类似于行,这样一来我们就将内容对比起来记忆学习了. 数据格式 MongoDB documents是BSON格式(一种类json的一种二进制形式的存

ASP.NET MVC学习系列(二)-WebAPI请求

继续接着上文 ASP.NET MVC学习系列(一)-WebAPI初探 来看看对于一般前台页面发起的get和post请求,我们在Web API中要如何来处理. 这里我使用Jquery 来发起异步请求实现数据调用. 继续使用上一文章中的示例,添加一个index.html页面,添加对jquery的引用. 一.无参数Get请求 一般的get请求我们可以使用jquery提供的$.get() 或者$.ajax({type:"get"}) 来实现: 请求的后台Action方法仍为上篇文章中的GetU

数据库MYSQL学习系列二

一.MYSQL数据库对象与应用 2.1-MySQL数据类型 Number不止一种 · 整形 · 浮点型 整形 · INT · SMALLINT · MEDIUMINT · BIGINT type Storage Minumun Value Maximum Value (Bytes) (Signed/Unsigned) (Signed/Unsigned) TINYINT 1 -128 127 0 255 SMALLINT 2 -32768 32767 0 65535 MEDIUMINT 3 -83

ASP.NET MVC学习系列(二)-WebAPI请求(转)

转自:http://www.cnblogs.com/babycool/p/3922738.html 继续接着上文 ASP.NET MVC学习系列(一)-WebAPI初探 来看看对于一般前台页面发起的get和post请求,我们在Web API中要如何来处理. 这里我使用Jquery 来发起异步请求实现数据调用. 继续使用上一文章中的示例,添加一个index.html页面,添加对jquery的引用. 一.无参数Get请求 一般的get请求我们可以使用jquery提供的$.get() 或者$.ajax

asp.net EF学习系列----深入理解查询延迟加载技术

ado.net EF是微软的一个ORM框架,使用过EF的同学都知道EF有一个延迟加载的技术. 如果你是一个老鸟,你可能了解一些,如果下面的学习过程中哪些方面讲解的不对,欢迎批评指教.如果一个菜鸟,那我们就一起开始今天的学习. 首先,提出以下几个问题. 何为延迟加载呢? 我们该如何使用呢? 我们为什么要使用延迟加载技术呢? 延迟加载技术有什么优.缺点呢? 好,带着上面的问题我们开始今天的学习. 1.何为延迟加载 EF的延迟加载,就是使用Lambda表达式或者Linq 从 EF实体对象中查询数据时,

SQL学习系列(二)之临时表的使用

1.关于使用临时表说明: (1).临时表其实是放在数据库tempdb里的一个用户表. (2).TempTableName必须带“#”,“#"可以是一个或者两个,以#(局部)或##(全局)开头的表,这种表在会话期间存在,会话结束则自动删除. (3).如果创建时不以#或##开头,而用tempdb.TempTable来命名它,则该表可在数据库重启前一直存在. 2.删除临时表 drop table  TempTableName (1).当存储过程完成时,将自动除去在存储过程中创建的本地临时表.由创建表的

Java学习系列(二十四)Java正则表达式详解

转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/45501777 前言 正则表达式可以说是用来处理字符串的一把利器,它是一个专门匹配n个字符串的字符串模板,本质是查找和替换.在实例演示之前先了解一下Pattern.Matcher这两个工具类,Pattern:编译好的带匹配的模板(如:Pattern.compile("[a-z]{2}");/ / 取2个小写字母):Matcher:匹配目标字符串后产生的结果(如:pattern.m

Java I/O系统学习系列二:输入和输出

编程语言的I/O类库中常使用流这个抽象概念,它代表任何有能力产出数据的数据源对象或者是有能力接收数据的接收端对象.“流”屏蔽了实际的I/O设备中处理数据的细节. 在这个系列的第一篇文章:<<Java I/O系统学习系列一:File和RandomAccessFile>>中,我们讲到RandomAccessFile可以写入和读取文件,具备I/O功能,但是其只能针对文件,而I/O还涉及到很多其他场景比如网络.读取内存中的字符串等,所以Java类库中提供了一系列的类库来对其进行支持,也就是

MySQL表的创建和表中数据操作

这篇文章主要介绍在navicat的命令界面操作mysql.主要涉及建立表结构,和对表中数据的增加删除修改查询等动作.站在一个新手角度的简单mysql表结构和数据操作. ☆ 准备工作 1,保证自己的电脑安装了mysql(my.ini下的字符集设置是utf8) 2,确保电脑同时安装navicat(任意版本) 3,保证mysql服务器已经启动 注:若对navicat操作不熟,请参照<<navicat从下载到使用>>这篇文章. ☆ 打开控制台 在navicat的tools(工具)菜单栏选择