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也是很久沒複習了 哈哈 有時間在看看書

相關文章
相關標籤/搜索