EF(二)--EF模型的配置

EF 的安裝

  1. 基礎階段用控制檯項目。使用NuGet 安裝EntityFramework。會自動在App.config中增加兩個entityFramework 相關配置段;

  2. 在 web.config 中配置連接字符串

    <add name="conn1" connectionString="Data Source=.;Initial Catalog=test1;UserID=sa;Password=123" providerName="System.Data.SqlClient" />
    

    易錯點:不能忘了寫providerName="System.Data.SqlClient"增加兩個entityFramework 相關配置段;

EF 簡單DataAnnotations 實體配置

  1. 數據庫中建表T_Perons,有Id(主鍵,自動增長)、Name、CreateDateTime字段。

  2. 創建Person類[Table(“T_Persons”)]因爲類名和表名不一樣,所以要使用Table標註

        [Table("T_Persons")]
        public class Person
        {
            public long ID { get; set; }
            public string Name { get; set; }
            public DateTime CreateTime { get; set; }
        }
    

    因爲EF約定主鍵字段名是Id,所以不用再特殊指定Id是主鍵,如果非要指定就指定[Key]。因爲字段名字和屬性名字一致,所以不用再特殊指定屬性和字段名的對應關係,如果需要特殊指定,則要用[Column(“Name”)]

    (*)必填字段標註[Required]、字段長度[MaxLength(5)]、可空字段用int?、如果字段在數據庫有默認值,則要在屬性上標註[DatabaseGenerated]注意實體類都要寫成public,否則後面可能會有麻煩。

  3. 創建DbContext類(模型類、實體類)

        public class MyDBContext: DbContext
        {
            //表示使用連接字符串中名字爲conn1 的去連接數據庫
            public MyDBContext() : base("name=strcon")
            {
    
            }
            //通過對Persons 集合的操作就可以完成對T_Persons的操作
            public DbSet<Person> Persons { get; set; }
        }
    
  4. 測試

            protected void Button1_Click(object sender, EventArgs e)
            {
                MyDBContext context = new MyDBContext();
                Person p=new Person();
                p.Name =TextBox1.Text;
                p.CreateTime = DateTime.Now;
                context.Persons.Add(p);
                context.SaveChanges();
            }
    

    注意:MyDbContext 對象是否需要using有爭議,不using也沒事。每次用的時候new MyDbContext就行,不用共享同一個實例,共享反而會有問題。SaveChanges()纔會把修改更新到數據庫中。

    EF的開發團隊都說要using DbContext,很多人不using,只是想利用LazyLoad 而已,但是那樣做是違反分層原則的。我的習慣還是using。

    異常的處理:如果數據有錯誤可能在SaveChanges()的時候出現異常,一般仔細查看異常信息或者一直深入一層層的鑽InnerException 就能發現錯誤信息。

    舉例:創建一個Person對象,不給Name、CreateDateTime賦值就保存。

EF 模型的兩種配置方式

EF 中的模型類的配置有DataAnnotations、FluentAPI 兩種。

上面這種在模型類上[Table(“T_Persons”)]、[Column(“Name”)]這種方式就叫DataAnnotations這種方式比較方便,但是耦合度太高,一般的類最好是POCO(Plain Old C# Object,沒有繼承什麼特殊的父類,沒有標註什麼特殊的Attribute,沒有定義什麼特殊的方法,就是一堆普通的屬性);不符合大項目開發的要求。微軟推薦使用FluentAPI
的使用方式,因此後面主要用FluentAPI 的使用方式。

FluentAPI 配置T_Persons 的方式

  1. 數據庫中建表T_Perons,有Id(主鍵,自動增長)、Name、CreateDateTime 字段。

  2. 創建 Person 類。模型類就是普通C#類

        public class Person
        {
            public long ID { get; set; }
            public string Name { get; set; }
            public DateTime CreateTime { get; set; }
        }
    
  3. 創建一個 PersonConfig 類,放到ModelConfig 文件夾下(PersonConfig、EntityConfig這樣的名字都不是必須的)

        public class PersonConfig : EntityTypeConfiguration<Person>
        {
            public PersonConfig()
            {
                this.ToTable("T_Person");
            }
        }
    
  4. 創建 DbContext 類

        public class MyDBContext:DbContext
        {
            public MyDBContext() : base("name=strcon")
            {
            }
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                base.OnModelCreating(modelBuilder);
                modelBuilder.Configurations.AddFromAssembly(Assembly.GetExecutingAssembly());
            }
            public DbSet<Person> Persons { get; set; }
        }
    

    下面這句話:

    modelBuilder.Configurations.AddFromAssembly(Assembly.GetExecutingAssembly());

    代表從這句話所在的程序集加載所有的繼承自EntityTypeConfiguration 爲模型配置類。還有很多加載配置文件的做法(把配置寫到OnModelCreating中或者把加載的代碼寫死到OnModelCreating 中),但是這種做法是最符合大項目規範的做法。

    和以前唯一的不同就是:模型不需要標註Attribute;編寫一個XXXConfig類配置映射關係;DbContext 中override OnModelCreating;

  5. 測試

            protected void Button1_Click(object sender, EventArgs e)
            {
                MyDBContext context = new MyDBContext();
                Person p = new Person();
                p.Name = TextBox1.Text;
                p.CreateTime = DateTime.Now;
                context.Persons.Add(p);
                context.SaveChanges();
            }
    

EF 的基本增刪改查

獲取DbSet除了可以ctx.Persons之外,還可以ctx.Set()。

  1. 增加,一個點:如果Id是自動增長的,創建的對象顯然不用指定Id的值,並且在SaveChanges ()後會自動給對象的Id屬性賦值爲新增行的Id字段的值。

  2. 刪除。先查詢出來要刪除的數據,然後Remove。這種方式問題最少,雖然性能略低,但是刪除操作一般不頻繁,不用考慮性能。後續在“狀態管理”中會講其他實現方法。

                MyDBContext context = new MyDBContext();
                if (e.CommandName=="BtnDelete")
                {
                    int id = Convert.ToInt32(e.CommandArgument);
                    var p = context.Persons.Where(per => per.ID == id).SingleOrDefault();
                    if (p!=null)
                    {
                        context.Persons.Remove(p);
                    }
                   int i= context.SaveChanges();
                    if (i>0)
                    {
                        Repeater1.DataSource = context.Persons.ToList();
                        Repeater1.DataBind();
                    }
                }
    

    怎麼批量刪除,比如刪除Id>3 的?查詢出來一個個Remove。性能坑爹。如果操作不頻繁或者數據量不大不用考慮性能,如果需要考慮性能就直接執行sql 語句

  3. 修改:先查詢出來要修改的數據,然後修改,然後SaveChanges()

    MyDbContext ctx = new MyDbContext();
    var ps = ctx.Persons.Where(p => p.Id > 3);
    foreach(var p in ps)
    {
        p.CreateDateTime = p.CreateDateTime.AddDays(3);
        p.Name = "haha";
    }
    ctx.SaveChanges();
    

    性能問題?同上。

  4. 查。因爲DbSet 實現了IQueryable 接口,而IQueryable 接口繼承了IEnumerable
    接口,所以可以使用所有的linq、lambda 操作。給表增加一個Age 字段,然後舉例orderby、groupby、where
    操作、分頁等。一樣一樣的。

  5. 查詢 order by 的一個細節

    EF調用Skip之前必須調用OrderBy:如下調用var items = ctx.Persons.Skip(3).Take(5); 會報錯“The method ‘OrderBy’ must be called before the method ‘Skip’.)”,要改成:var items = ctx.Persons.OrderBy(p=>p.CreateDateTime).Skip(3).Take(5);

    這也是一個好習慣,因爲以前就發生過(寫原始sql):分頁查詢的時候沒有指定排序規則,以爲默認是按照Id 排序,其實有的時候不是,就造成數據混亂。寫原始SQL 的時候也要注意一定要指定排序規則。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章