上一篇寫了《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也是好久沒復習了 哈哈 有時間在看看書