EF使用CodeFirst方式生成數據庫&技巧經驗


前言

EF已經發布很久了,也有越來越多的人在使用EF。如果你已經能夠非常熟練的使用EF的功能,那么就不需要看了。本文意在將自己使用EF的方式記錄下來備忘,也是為了給剛剛入門的同學一些指導。看完此文,你應該就學會以CodeFirst的方式操作數據庫了。

本文主要內容

  • CodeFirst生成數據庫的流程
  • 初始化配置
  • 數據庫實體構造技巧
  • 主外鍵設置
  • decimal精度修改

項目框架搭建

本文所使用的開發工具是vs2015(EF6.1.3)

第一步:新建一個空白項目

第二步:引用EntityFramework

 

DbContext的初始化配置

 DbContext作為操作數據庫的網關,十分重要。我們需要對它進行一些類的初始化操作,例如:解決團隊開發中,多人遷移數據庫造成的修改覆蓋問題

代碼如下:

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity.ModelConfiguration.Conventions;
namespace EFDemo.Core.EF
{
    /// <summary>
    /// EF訪問數據庫的接口   
    /// </summary>
    public class MyDbContext : System.Data.Entity.DbContext
    {        
        public MyDbContext()
            : base("EFDemo")
        {
            //解決團隊開發中,多人遷移數據庫造成的修改覆蓋問題。
            Database.SetInitializer<MyDbContext>(null);
            //base.Configuration.AutoDetectChangesEnabled = false;
            ////關閉EF6.x 默認自動生成null判斷語句
            //base.Configuration.UseDatabaseNullSemantics = true;           
        }    
        public MyDbContext(System.Data.Common.DbConnection oConnection)
            : base(oConnection, true)
        {
            this.Configuration.LazyLoadingEnabled = true;         
        }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            //表名不用復數形式
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
            //移除一對多的級聯刪除約定,想要級聯刪除可以在 EntityTypeConfiguration<TEntity>的實現類中進行控制
            modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
            //多對多啟用級聯刪除約定,不想級聯刪除可以在刪除前判斷關聯的數據進行攔截
            modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();          

            base.OnModelCreating(modelBuilder);
        }
        //將實體對象寫在這里,就可以生成對應的數據。 如下:
        //public DbSet<Demo> Demo { get; set; }


  

    }


}

項目位置:

Migrations下Configuration類的初始化配置

 Configuration類的初始化配置十分重要,我們需要通過配置解決一系列遷移問題。例如:允許自動遷移,自動遷移默認情況下不扔掉列在我們的數據庫中的表。如果我們不希望這樣的行為,我們可以告訴遷移明確允許數據丟失的配置類的AutomaticMigrationDataLossAllowed屬性設置為true。

代碼如下:

namespace EFDemo.Core.Migrations
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Migrations;
    using System.Linq;

    internal sealed class Configuration : DbMigrationsConfiguration<EFDemo.Core.EF.MyDbContext>
    {
        public Configuration()
        {
            //允許自動遷移
            //不然會報錯Unable to update database to match the current model because there are pending changes and automatic migration is disabled. Either write the pending model changes to a code-based migration or enable automatic migration. Set DbMigrationsConfiguration.AutomaticMigrationsEnabled to true to enable automatic migration.You can use the Add-Migration command to write the pending model changes to a code-based migration.

            //允許自動遷移
            AutomaticMigrationsEnabled = true;
            //自動遷移默認情況下不扔掉列在我們的數據庫中的表。如果我們不希望這樣的行為,我們可以告訴遷移明確允許數據丟失的配置類的AutomaticMigrationDataLossAllowed屬性設置為true。
            AutomaticMigrationDataLossAllowed = true;
        }

        protected override void Seed(EF.MyDbContext context)
        {
            
            //  This method will be called after migrating to the latest version.

            //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
            //  to avoid creating duplicate seed data. E.g.
            //
            //    context.People.AddOrUpdate(
            //      p => p.FullName,
            //      new Person { FullName = "Andrew Peters" },
            //      new Person { FullName = "Brice Lambson" },
            //      new Person { FullName = "Rowan Miller" }
            //    );
            //
        }
    }
}

項目位置:

數據庫對應實體對象的定義

 CodeFirst模式需要我們先定義實體,然后通過實體生成數據。

通常我們設計數據庫表時,每個表都有(ID,是否刪除,備注,添加人,添加時間,修改人,修改時間)等字段。我們可以用基類處理

基類實體:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EFDemo.Core.Entity
{
    public class BaseEntity
    {

    }
    [Serializable]
    public class BaseEntity<TKey> : BaseEntity
    {
        public BaseEntity()
        {
            this.AddTime = DateTime.Now;
        }

        [Key]
        [Display(Name = "編號")]
        public TKey ID { get; set; }
        [Display(Name = "排序")]
        [Required(ErrorMessage = "{0}是必填項"), Range(0, int.MaxValue, ErrorMessage = "{0}的范圍是{1}到{2}")]
        [DefaultValue(0)]
        public int Sort { get; set; }
        [Display(Name = "備注")]
        [MaxLength(256, ErrorMessage = "{0}最大長度{1}")]
        public string Remark { get; set; }
        [Display(Name = "是否刪除")]
        [Required]
        public bool Deleted { get; set; }
        public int AddUser { get; set; }
        [Display(Name = "添加時間")]
        [DisplayFormat(ApplyFormatInEditMode = true, ConvertEmptyStringToNull = true, DataFormatString = "{0:yyyy-MM-dd HH mm}", HtmlEncode = false, NullDisplayText = "數據無效")]
        public DateTime AddTime { get; set; }
        public int ModUser { get; set; }
        [DisplayFormat(ApplyFormatInEditMode = true, ConvertEmptyStringToNull = true, DataFormatString = "{0:yyyy-MM-dd  HH mm}", HtmlEncode = false, NullDisplayText = "數據無效")]
        public DateTime? ModTime { get; set; }

    }
  

}
View Code

省市區表:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EFDemo.Core.Entity
{
    /// <summary>
    /// 省市區
    /// </summary>
    public class Public_Area
    {        

        [Key]
        public Guid ID { get; set; }

        [Display(Name = "父親ID")]
        public Guid ParentID { get; set; }

        [Display(Name = "名稱")]
        [MaxLength(32, ErrorMessage = "{0}最大長度{1}")]
        public String Name { get; set; }
    }
}
View Code

班級表:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EFDemo.Core.Entity
{
    /// <summary>
    /// 班級
    /// </summary>
   public class T_Classes : BaseEntity<int>
    {
        public T_Classes() {
            this.T_Student = new List<Entity.T_Student>();
        }


        [InverseProperty("T_Classes")]
        public virtual List<T_Student> T_Student { get; set; }

        [Display(Name = "班級名稱")]
        [Required(ErrorMessage = "{0}是必填項")]
        [MaxLength(8, ErrorMessage = "{0}最大長度{1}")]
        public string Name { get; set; }

        [Display(Name = "人數")]
        public int Count { get; set; }

        [Display(Name = "班級經費")]
        public decimal Money { get; set; }
    }
}
View Code

 

學生表:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EFDemo.Core.Entity
{
    /// <summary>
    /// 學生
    /// </summary>
    public class T_Student : BaseEntity<int>
    {

        /// <summary>
        /// 外鍵
        /// </summary>
        [ForeignKey("ClassesID")]
        public virtual T_Classes T_Classes { get; set; }
        [Display(Name = "班級ID")]
        public int ClassesID { get; set; }

        [Display(Name = "姓名")]
        [Required(ErrorMessage = "{0}是必填項")]
        [MaxLength(8, ErrorMessage = "{0}最大長度{1}")]
        public string Name { get; set; }

        [Display(Name = "性別")]
        public bool Sex { get; set; }

        [Display(Name = "年齡")]
        public int Age { get; set; }

        [Display(Name = "電話")]
        [Required(ErrorMessage = "{0}是必填項")]
        [RegularExpression(@"^(13[0-9]|15[0-9]|18[0-9])\d{8}$", ErrorMessage = "不是手機號格式")]
        [MaxLength(11, ErrorMessage = "{0}最大長度{1}")]
        public string Phone { get; set; }


        /// <summary>
        /// 省市縣外鍵
        /// </summary>

        [ForeignKey("ProvinceID")]
        public virtual Public_Area Public_Area_Province { get; set; }
        [Display(Name = "省ID")]
        public Guid ProvinceID { get; set; }

        [ForeignKey("CityID")]
        public virtual Public_Area Public_Area_City { get; set; }
        [Display(Name = "市ID")]
        public Guid CityID { get; set; }

        [ForeignKey("CountyID")]
        public virtual Public_Area Public_Area_County { get; set; }
        [Display(Name = "縣ID")]
        public Guid CountyID { get; set; }
    }
}
View Code

 

班級表和學生表是一對多的關系,省市區表和學生表是一對多的關系,同時學生表中有多個省市區表的外鍵。

項目位置:

 

使用命令生成數據庫

第一步:將實體對象加入到DbContext中,

如下:

//將實體對象寫在這里,就可以生成對應的數據。 如下:
        //public DbSet<Demo> Demo { get; set; }

        public DbSet<Public_Area> Public_Area { get; set; }
        public DbSet<T_Classes> T_Classes { get; set; }
        public DbSet<T_Student> T_Student { get; set; }

第二步:在EFDemo.Core項目下的App.config文件夾中添加生成數據庫的配置項

 

 

配置文件代碼如下:

name="EFDemo"中的EFDemo要和DbContex中的一致。 
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <connectionStrings>
    <!--生成數據庫的連接字符串-->
    <add name="EFDemo" connectionString="Data Source=.;Initial Catalog=EFDemoDB;User ID=sa;Password=123456;MultipleActiveResultSets=True;Application Name=EntityFramework" providerName="System.Data.SqlClient" />
  </connectionStrings>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="mssqllocaldb" />
      </parameters>
    </defaultConnectionFactory>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
</configuration>

 

第三步:執行更新命令

啟動項目一定要選擇EFDemo.Core

生成數據庫如下:

主外鍵關系設置

 班級和學生一對多關系的設置:

一個表中的多個外鍵是另一個表中的主鍵的情況:學生表和省市縣表

生成的數據庫如下:

需要注意的是:這種情況,在Public_Area表中不能反向設置 public virtual List<T_Student> T_Student ,不然會報錯。

 

decimal怎么保存四位小數  

 decimal默認保留兩位小數,我們需要通過如下設置讓其保留四位小數。

在DbContext中配置班級表中的Money字段讓其保留四位小數:

 執行Update-Database命令:

結果如下:

 

 

  

使用EF操作數據庫數據

第一步:

 讓EFDemo.Web應用EFDemo.Core程序集。

第二步:

配置EFDemo.Web中的webconfig中的數據庫連接字符串:

 <connectionStrings>
    <!--操作數據庫的連接字符串-->
    <add name="EFDemo" connectionString="Data Source=.;Initial Catalog=EFDemoDB;User ID=sa;Password=123456;MultipleActiveResultSets=True;Application Name=EntityFramework" providerName="System.Data.SqlClient" />
  </connectionStrings>

第三步:

使用EF向數據庫添加數據

    public ActionResult Index()
        {
            using (var db = new Core.EF.MyDbContext())
            {
                Public_Area area1 = new Public_Area()
                {
                    ID = Guid.NewGuid(),
                    Name = "河南",
                    ParentID = Guid.NewGuid()

                };
                db.Public_Area.Add(area1);
                Public_Area area2 = new Public_Area()
                {
                    ID = Guid.NewGuid(),
                    Name = "鄭州",
                    ParentID = area1.ID

                };
                db.Public_Area.Add(area2);
                Public_Area area3 = new Public_Area()
                {
                    ID = Guid.NewGuid(),
                    Name = "新鄭",
                    ParentID = area2.ID

                };
                db.Public_Area.Add(area3);

                //添加測試數據
                T_Classes classes = new T_Classes()
                {
                    Name = "高中三班",
                    Money = 2000
                };
                db.T_Classes.Add(classes);
                T_Student student = new T_Student()
                {
                    ClassesID = classes.ID,
                    Name = "張三",
                    Phone = "15236265820",
                    Sex = true,
                    ProvinceID = area1.ID,
                    CityID = area2.ID,
                    CountyID = area3.ID,
                };
                db.T_Student.Add(student);
                db.SaveChanges();
            }
            return View();
        }

第四步:

查看數據庫數據

 

Demo完整代碼下載

EFDemo.Core.7z

 

下一篇:EF查詢之性能優化技巧

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM