上一篇寫了《Entity Farmework領域建模方式 3種編程方式》,現在就Code First 繼續學習 1、資料庫表的創建 新建一個MVC的項目,在引用右擊管理NuGet程式包,點擊瀏覽搜索EF安裝,我這裡主要是EF6.0 以上的學習 所以都安裝6.0 以上的版本 接下來在Model文件夾下 ...
上一篇寫了《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也是好久沒複習了 哈哈 有時間在看看書