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

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

一、数据库表的建立

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

 

 

 

 

接下来在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中调用,启动就生成了数据库app

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

 

 

 

 

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

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

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里面用)ui

 

 

 

 

 

 

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

三、三者约定之 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; }
    }

 

 

 

 

 

 

 

四、三者约定之 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也是很久没复习了 哈哈 有时间在看看书

相关文章
相关标签/搜索