日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

sql注入pythonpoco_.NET EF(Entity Framework)详解

發布時間:2023/12/15 python 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 sql注入pythonpoco_.NET EF(Entity Framework)详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一丶Entity Framework

(一)EF簡介

(1)ORM:Object Relation Mapping ,通俗說:用操作對象的方式來操作數據庫。

(2)插入數據庫不再是執行Insert,而是類似于Person p = new Person();p.Age=3;p.Name=“英萊特”;db.Save§;這樣的做法。

(3)ORM工具有很多Dapper、PetaPoco、NHibernate,最首推的還是微軟官方的Entity Framework,簡稱EF。

(4)EF底層仍然是對ADO.Net的封裝。EF支持SQLServer、MYSQL、Oracle、Sqlite等所有主流數據庫。

(5)使用EF進行數據庫開發的時候有兩個東西建:建數據庫(T_Persons),建模型類(Person)。根據這兩種創建的先后順序有EF的三種創建方法:

DataBase First(數據庫優先):先創建數據庫表,然后自動生成EDM文件,EDM文件生成模型類。簡單展示一下DataBase First 的使用。

Model First(模型優先):先創建Edm文件,Edm文件自動生成模型類和數據庫;

Code First(代碼優先):程序員自己寫模型類,然后自動生成數據庫。沒有Edm。

DataBase First 簡單、方便,但是當項目大了之后會非常痛苦;

Code First 入門門檻高,但是適合于大項目。

Model First……

無論哪種First,一旦創建好了數據庫、模型類之后,后面的用法都是一樣的。業界都是推薦使用Code First,新版的EF中只支持Code First,因此我們這里只講Code First。

(6)Code First的微軟的推薦用法是程序員只寫模型類,數據庫由EF 幫我們生成,當修改模型類之后,EF 使用“DB Migration”自動幫我們更改數據庫。但是這種做法太激進,不適合很多大項目的開發流程和優化,只適合于項目的初始開發階段。Java的Hibernate 中也有類似的DDL2SQL 技術,但是也是用的較少。“DB Migration”也不利于理解EF,因此在初學階段,我們將會禁用“DB Migration”,采用更實際的“手動建數據庫和模型類”的方式。

(7)如果大家用過 NHibernate 等ORM 工具的話,會發現開發過程特別麻煩,需要在配置文件中指定模型類屬性和數據庫字段的對應關系,哪怕名字完全也一樣也要手動配置。使用過Java 中Struts、Spring 等技術的同學也有過類似“配置文件地獄”的感覺。 像ASP.Net MVC 一樣,EF 也是采用“約定大于配置”這樣的框架設計原則,省去了很多配置,能用約定就不要自己配置。

在.Net Framework SP1微軟包含一個實體框架(Entity Framework),此框架可以理解成微軟的一個ORM產品。用于支持開發人員通過對概念性應用程序模型編程(而不是直接對關系存儲架構編程)來創建數據訪問應用程序。目標是降低面向數據的應用程序所需的代碼量并減輕維護工作。

(二)Entity Framework應用程序有以下優點:

(1)應用程序可以通過更加以應用程序為中心的概念性模型(包括具有繼承性、復雜成員和關系的類型)來工作。

(2)應用程序不再對特定的數據引擎或存儲架構具有硬編碼依賴性。

(3)可以在不更改應用程序代碼的情況下更改概念性模型與特定于存儲的架構之間的映射。

(4)開發人員可以使用可映射到各種存儲架構(可能在不同的數據庫管理系統中實現)的一致的應用程序對象模型。

(5)多個概念性模型可以映射到同一個存儲架構。

(6)語言集成查詢支持可為查詢提供針對概念性模型的編譯時語法驗證。

實體框架Entity Framework是 DO.NET中的一組支持開發面向數據的軟件應用程序的技術。在EF中的實體數據模型(EDM)由以下三種模型和具有相應文件擴展名的映射文件進行定義。

概念架構定義語言文件 (.csdl) – 定義概念模型。

存儲架構定義語言文件 (.ssdl) – 定義存儲模型(又稱邏輯模型)。

映射規范語言文件 (.msl) – 定義存儲模型與概念模型之間的映射。

實體框架使用這些基于XML的模型和映射文件將對概念模型中的實體和關系的創建、讀取、更新和刪除操作轉換為數據源中的等效操作。EDM甚至支持將概念模型中的實體映射到數據源中的存儲過程。它提供以下方式用于查詢 EDM 并返回對象:

LINQ to Entities–提供語言集成查詢(LINQ)支持用于查詢在概念模型中定義的實體類型。

Entity SQL – 與存儲無關的SQL方言,直接使用概念模型中的實體并支持諸如繼承和關系等 EDM 功能。

查詢生成器方法 --可以使用LINQ風格的查詢方法構造 Entity SQL 查詢。

(三)相關知識復習

(1)var類型推斷:var p =new Person();

(2)匿名類型。var a =new {p.Name,Age=5,Gender=p.Gender,Name1=a.Name};//{p.Name}=={Name=p.Name}

(3)給新創建對象的屬性賦值的簡化方法:Person p = new Person{Name=“tom”,Age=5};等價于Person p = new Person();p.Name=“tom”;p.Age=5;

(四)lambda表達式:

函數式編程,在Entity framework編程中用的很多

Actional= delegate(int i) { Console.Writeline(i); };

可以簡化成(=>讀作goes to) :

Action< int> a2 = (inti) = > { Console.Writeline(i); };

還可以省略參數類型(編譯器會自動根據委托類型推斷):

Action< int> a3 = (i) = > { Console.Writeline(i); };

如果只有一個參數還可以省略參數的小括號(多個參數不行)

Actiona4 = i = > { Console.Writeline(i); };

如果委托有返回值,并且方法體只有一行代碼,這一行代碼還是返回值,那么就可以連方法的大括號和return都省略:

Funcfl= delegate(int i, int j) { return "結果是" + (i + j); };

Funcf2= (i,j)=>"結果是"+ (i+ j);

(五)集合常用擴展方法

where (支持委托)、Select (支持委托)、Max 、Min 、OrderBy

First (獲取第一個,如果一個都沒有則異常)

FirstOrDefault (獲取第一個,如果—個都沒有則返回默認值)

Single (獲取唯一一個,如果沒有或者有多個則異常)

SingleOrDefoult (獲取唯一一個, 如果沒有則返回默認值,如果有多個則異常)

注意lambda中照樣要避免變量重名的問題:var p =persons.Where(p => p.Name ==“yltedu.com”).First();

(六)高級集合擴展方法

//學生

public class Person

{

public string Name { get; set; }

public int Age { get; set; }

public bool Gender { get; set; }

public int Salary { get; set; }

public override string ToString()

{

return string.Format("Name={0},Age={1},Gender={2},Salary={3}",Name, Age, Gender, Salary);

}

}

//老師

public class Teacher

{

public Teacher()

{

this.Students=new List();

}

public string Name { get; set; }

public ListStudents { get; set; }

}

var s0 =new Person { Name="tom",Age=3,Gender=true,Salary=6000};

var s1 = new Person { Name = "jerry", Age = 8, Gender = true, Salary = 5000 };

var s2 = new Person { Name = "jim", Age = 3, Gender = true, Salary = 3000 };

var s3 = new Person { Name = "lily", Age = 5, Gender = false, Salary = 9000 };

var s4 = new Person { Name = "lucy", Age = 6, Gender = false, Salary = 2000 };

var s5 = new Person { Name = "kimi", Age = 5, Gender = true, Salary = 1000 };

Listlist = new List();

list.Add(s0);

list.Add(s1);

list.Add(s2);

list.Add(s3);

list.Add(s4);

list.Add(s5);

Teacher t1 = new Teacher { Name="英萊特.net"};

t1.Students.Add(s1);

t1.Students.Add(s2);

Teacher t2 = new Teacher { Name = "英萊特Python" };

t2.Students.Add(s2);

t2.Students.Add(s3);

t2.Students.Add(s5);

Teacher[] teachers = { t1,t2};

(1)Any(),判斷集合是否包含元素,返回值是bool,一般比Cout()>0 效率高。Any還可以指定條件表達式。

bool b = list.Any(p => p.Age > 50); 等價于bool b =list.Where(p=>p.Age>50).Any();

(2)Distinct(),剔除完全重復數據。(*)注意自定義對象的Equals 問題:需要重寫Equals 和GetHashCode 方法來進行內容比較。

(3)排序:升序list.OrderBy(p=>p.Age);降序list.OrderByDescending(p=>p.Age)。指定多個排序規 則,而不是多個OrderBy,而是:list.OrderByDescending(p=>p.Age).ThenBy(p=>p.Salary),也支 持ThenByDescending()。注意這些操作不會影響原始的集合數據。

(4)Skip(n)跳過前n條數據;

(5)Take(n)獲取最多n條數據,如果不足n條也不會報錯。常用來分頁獲取數據。

(6)list.Skip(3).Take(2)跳過前3條數據獲取2條數據。

(7)Except(items1)排除當前集合中在items1中存在的元素。用int數組舉例。

(8)Union(items1)把當前集合和items1中組合。用int 數組舉例。

(9)Intersect(items1) 把當前集合和items1 中取交集。用int 數組舉例。

(10)分組:

foreach(var g in list.GroupBy(p => p.Age))

{

Console.WriteLine(g.Key+":"+g.Average(p=>p.Salary));

}

(11)SelectMany:把集合中每個對象的另外集合屬性的值重新拼接為一個新的集合

foreach(var s in teachers.SelectMany(t => t.Students))

{

Console.WriteLine(s);//每個元素都是Person

}

}

注意不會去重,如果需要去重要自己再次調用Distinct()

(12)Join

class Master

{

public long Id { get; set; }

public string Name { get; set; }

}

class Dog

{

public long Id { get; set; }

public long MasterId { get; set; }

public string Name { get; set; }

}

Master m1 = new Master { Id = 1, Name = "英萊特" };

Master m2 = new Master { Id = 2, Name = "比爾蓋茨" };

Master m3 = new Master { Id = 3, Name = "周星馳" };

Master[] masters = { m1,m2,m3};

Dog d1 = new Dog { Id = 1, MasterId = 3, Name = "旺財" };

Dog d2 = new Dog { Id = 2, MasterId = 3, Name = "汪汪" };

Dog d3 = new Dog { Id = 3, MasterId = 1, Name = "京巴" };

Dog d4 = new Dog { Id = 4, MasterId = 2, Name = "泰迪" };

Dog d5 = new Dog { Id = 5, MasterId = 1, Name = "中華田園" };

Dog[] dogs = { d1, d2, d3, d4, d5 };

Join 可以實現和數據庫一樣的Join 效果,對有關聯關系的數據進行聯合查詢 下面的語句查詢所有Id=1 的狗,并且查詢狗的主人的姓名。

var result = dogs.Where(d => d.Id > 1).Join(masters, d => d.MasterId, m => m.Id,(d,m)=>new {DogName=d.Name,MasterName=m.Name});

foreach(var item in result)

{

Console.WriteLine(item.DogName+","+item.MasterName);

}

(七)EF 的安裝

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

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

易錯點:不能忘了寫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 DbSetPersons { 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{

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 DbSetPersons { 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 的時候也要注意一定要指定排序規則。

(三)EF 原理及SQL 監控

EF 會自動把Where()、OrderBy()、Select()等這些編譯成“表達式樹(Expression Tree)”,然后會把表達式樹翻譯成SQL 語句去執行。(編譯原理,AST)因此不是“把數據都取到內存中,然后使用集合的方法進行數據過濾”,因此性能不會低。但是如果這個操作不能被翻譯成SQL語句,則或者報錯,或者被放到內存中操作,性能就會非常低。

(1)怎么查看真正執行的SQL是什么樣呢?

DbContext有一個Database屬性,其中的Log屬性,是Action委托類型,也就是可以指向一個void A(string s)方法,其中的參數就是執行的SQL語句,每次EF執行SQL語句的時候都會執行Log。因此就可以知道執行了什么SQL。

EF的查詢是“延遲執行”的,只有遍歷結果集的時候才執行select 查詢,ToList()內部也是遍歷結果集形成List。

查看Update操作,會發現只更新了修改的字段。

(2)觀察一下前面學學習時候執行的SQL是什么樣的。Skip().Take()被翻譯成了?Count()被翻譯成了?

var result = ctx.Persons.Where(p => p.Name.StartsWith("inlett"));//看看翻譯成了什么?

var result = ctx.Persons.Where(p => p.Name.Contains("com"));

var result = ctx.Persons.Where(p => p.Name.Length>5);

var result = ctx.Persons.Where(p => p.CreateDateTime>DateTime.Now);

long[] ids = { 2,5,6};//不要寫成int[]

var result = ctx.Persons.Where(p => ids.Contains(p.Id));

(3)EF中還可以多次指定where來實現動態的復合檢索:

//必須寫成IQueryable,如果寫成IEnumerable 就會在內存中取后續數據

IQueryableitems = ctx.Persons;//為什么把IQueryable換成var 會編譯出錯

items = items.Where(p=>p.Name=="inlett");

items = items.Where(p=>p.Id>5);

查看一下生成的SQL語句。

(4)EF是跨數據庫的,如果遷移到MYSQL上,就會翻譯成MYSQL的語法。要配置對應數據庫的Entity Framework Provider。

(5)細節:

每次開始執行的__MigrationHistory等這些SQL語句是什么?是DBMigration用的,也就是由EF幫我們建數據庫,現在我們用不到,用下面的代碼禁用:

Database.SetInitializer(null);

XXXDbContext就是項目DbContext的類名。一般建議放到XXXDbContext構造函數中。注意這里的Database 是System.Data.Entity下的類,不是DbContext的Database屬性。如果寫到DbContext中,最好用上全名,防止出錯。

(四)執行原始SQL

不要“手里有錘子,到處都是釘子”在一些特殊場合,需要執行原生SQL。

執行非查詢語句,調用DbContext的Database屬性的ExecuteSqlCommand方法,可以通過占位符的方式傳遞參數:

ctx.Database.ExecuteSqlCommand("update T_Persons set Name={0},CreateDateTime=GetDate()","YLT.com");

占位符的方式不是字符串拼接,經過觀察生成的SQL語句,發現仍然是參數化查詢,因此不會有SQL注入漏洞。

執行查詢:

var q1 = ctx.Database.SqlQuery("select Name,Count(*) Count from T_Persons where Id>{0} and CreateDateTime<={1} group by Name",2, DateTime.Now); //返回值是DbRawSqlQuery類型,也是實現IEnumerable 接口

foreach(var item in q1)

{

Console.WriteLine(item.Name+":"+item.Count);

}

class Item1

{

public string Name { get; set; }

public int Count { get; set; }

}

類似于ExecuteScalar的操作比較麻煩:

int c = ctx.Database.SqlQuery("select count(*) from T_Persons").SingleOrDefault();

(五)不是所有lambda 寫法都能被支持

下面想把Id轉換為字符串比較一下是否為"3"(別管為什么):

var result = ctx.Persons.Where(p => Convert.ToString(p.Id)=="3");

運行會報錯(也許高版本支持了就不報錯了),這是一個語法、邏輯上合法的寫法,但是EF目前無法把他解析為一個SQL語句。

出現“System.NotSupportedException”異常一般就說明你的寫法無法翻譯成SQL語句

想獲取創建日期早于當前時間一小時以上的數據:

var result = ctx.Persons.Where(p => (DateTime.Now - p.CreateDateTime).TotalHours>1);

同樣也可能會報錯。

怎么解決?

嘗試其他替代方案(沒有依據,只能亂試):

var result = ctx.Persons.Where(p => p.Id==3);

EF中提供了一個SQLServer專用的類SqlFunctions,對于EF不支持的函數提供了支持,比如:

var result = ctx.Persons.Where(p =>SqlFunctions.DateDiff("hour",p.CreateDateTime,DateTime.Now)>1);

(六)EF對象的狀態

簡介

為什么查詢出來的對象Remove()、再SaveChanges()就會把數據刪除。而自己new一個Person()對象,然后Remove()不行?為什么查詢出來的對象修改屬性值后、再SaveChanges()就會把數據庫中的數據修改。

因為EF會跟蹤對象狀態的改變。

EF中中對象有五個狀態:Detached(游離態,脫離態)、Unchanged(未改變)、Added(新增)、Deleted(刪除)、Modified(被修改)。

Add()、Remove()修改對象的狀態。所有狀態之間幾乎都可以通過:Entry§.State=xxx的方式進行強制狀態轉換。

通過代碼來演示一下。這個狀態轉換圖沒必要記住,了解即可。

狀態改變都是依賴于Id的(Added除外)

應用(*)

當SavaChanged()方法執行期間,會查看當前對象的EntityState的值,決定是去新增(Added)、修改Modified)、刪除(Deleted)或者什么也不做(UnChanged)。下面的做法不推薦,在舊版本中一些寫法不被支持,到新版EF中可能也會不支持。

(1)不先查詢再修改再保存,而是直接更新部分字段的方法

var p = new Person();

p.Id = 2;

ctx.Entry(p).State = System.Data.Entity.EntityState.Unchanged;

p.Name = "adfad";

ctx.SaveChanges();

也可以:

var p = new Person();

p.Id = 5;

p.Name = "yltedu";

ctx.Persons.Attach(p);//等價于ctx.Entry(p).State = System.Data.Entity.EntityState.Unchanged;

ctx.Entry(p).Property(a => a.Name).IsModified = true;

ctx.SaveChanges();

(2)不先查詢再Remove再保存,而是直接根據Id刪除的方法:

var p = new Person();

p.Id = 2;

ctx.Entry(p).State = System.Data.Entity.EntityState.Deleted;

ctx.SaveChanges();

注意下面的做法并不會刪除所有Name=“ylt.com” 的,因為更新、刪除等都是根據Id進行的:

var p = new Person();

p.Name = "yltedu.com";

ctx.Entry(p).State = System.Data.Entity.EntityState.Deleted;

ctx.SaveChanges();

上面其實是在:

delete * from t_persons where Id=0

EF優化的一個技巧

如果查詢出來的對象只是供顯示使用,不會修改、刪除后保存,那么可以使用AsNoTracking()來使得查詢出來的對象是Detached狀態,這樣對對象的修改也還是Detached狀態,EF不再跟蹤這個對象狀態的改變,能夠提升性能。

var p1 = ctx.Persons.Where(p => p.Name == "rupeng.com").FirstOrDefault();

Console.WriteLine(ctx.Entry(p1).State);

改成:

var p1 = ctx.Persons.AsNoTracking().Where(p => p.Name == "rupeng.com").FirstOrDefault();

Console.WriteLine(ctx.Entry(p1).State);

因為AsNoTracking()是DbQuery類(DbSet的父類)的方法,所以要先在DbSet后調用AsNoTracking()。

Fluent API更多配置

基本EF配置只要配置實體類和表、字段的對應關系、表間關聯關系即可。如果利用EF的高級配置,可以達到更多效果:如果數據錯誤(比如字段不能為空、字符串超長等),會在EF層就會報錯,而不會被提交給數據庫服務器再報錯;如果使用自動生成數據庫,也能幫助EF生成更完美的數據庫表。

這些配置方法無論是DataAnnotations、FluentAPI都支持,下面講FluentAPI的用法,DataAnnotations感興趣的自己查(http://blog.csdn.net/beglorious/article/details/39637475)。

盡量用約定,EF配置越少越好。Simple is best 參考資料:http://www.cnblogs.com/nianming/archive/2012/11/07/2757997.html

HasMaxLength設定字段的最大長度

public PersonConfig()

{

this.ToTable("T_Persons");

this.Property(p => p.Name).HasMaxLength(50);//長度為50

}

依賴于數據庫的“字段長度、是否為空”等的約束是在數據提交到數據庫服務器的時候才會檢查;EF的配置,則是由EF來檢查的,如果檢查出錯,根本不會被提交給服務器。

如果插入一個Person對象,Name屬性的值非常長,保存的時候就會報DbEntityValidationException異常,這個異常的Message中看不到詳細的報錯消息,要看EntityValidationErrors屬性的值。

var p = new Person();

p.Name = "非常長的字符串";

ctx.Persons.Add(p);

try

{

ctx.SaveChanges();

}

catch(DbEntityValidationException ex)

{

StringBuilder sb = new StringBuilder();

foreach(var ve in ex.EntityValidationErrors.SelectMany(eve=>eve.ValidationErrors))

{

sb.AppendLine(ve.PropertyName+":"+ve.ErrorMessage);

}

Console.WriteLine(sb);

}

(有用)字段是否可空

this.Property(p => p.Name).IsRequired() 屬性不能為空;

this.Property(p => p.Name).IsOptional() 屬性可以為空;(沒用的雞肋!)

EF默認規則是“主鍵屬性不允許為空,引用類型允許為空,可空的值類型long?等允許為空,值類型不允許為空。”基于“盡量少配置”的原則:如果屬性是值類型并且允許為null,就聲明成long?等,否則聲明成long等;如果屬性屬性值是引用類型,只有不允許為空的時候設置IsRequired()。

其他一般不用設置的(了解即可)

(1)主鍵:this.HasKey(p => p.pId);

(2)某個字段不參與映射數據庫:this.Ignore(p => p.Name1);

(3)this.Property(p => p.Name).IsFixedLength(); 是否對應固定長度

(4)this.Property(p => p.Name).IsUnicode(false) 對應的數據庫類型是varchar類型,而不是nvarchar

(5)this.Property(p => p.Id).HasColumnName(“Id1”); Id列對應數據庫中名字為Id的字段

(6)this.Property(p=>p.Id).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity) 指定字段是自動增長類型。

流動起來

因為ToTable()、Property()、IsRequired()等方法的還是配置對象本身,因此可以實現類似于StringBuilder的鏈式編程,這就是“Fluent”一詞的含義; 因此下面的寫法:

public PersonConfig ()

{

this. ToTabl e ("T—Persons");

this.HasKey(p => p. Id);

this. Ignore(p => p. Name2);

this.Property(p => p.Name) . HasMaxLength (50);

this. Property (p => p. Name) . I sRequired ();

this.Property(p => p.CreateDateTime) . HasCol umnName ("CreateDateTi me");

this. Property (p => p. Name) . I sRequired () ;

}

可以簡化成:

public PersonConfig()

{

this. ToTable ("T_Persons") . HasKey (p => p. Id). Ignore (p => p. Name2) ;

this. Property (p => p. Name) . HasMaxLength (50). IsRequired O ;

this. Property (p => p. CreateDateTime) . HasColumnName ("CreateDateTime") . IsRequiredO;

}

后面用的時候都Database.SetInitializer(null);

一對多關系映射

EF最有魅力的地方在于對于多表間關系的映射,可以簡化工作。 復習一下表間關系:

(1)一對多(多對一):一個班級對應著多個學生,一個學生對著一個班級。一方是另外一方的唯一。在多端有一個指向一端的外鍵。舉例:班級表:T_Classes(Id,Name) 學生表

T_Students(Id,Name,Age,ClassId)

(2)多對多:一個老師對應多個學生,一個學生對于多個老師。任何一方都不是對方的唯一。 需要一個中間關系表。具體: 學生表T_Students(Id,Name,Age,ClassId) , 老師表 T_Teachers(Id,Name,PhoneNum),關系表T_StudentsTeachers(Id,StudentId,TeacherId)

和關系映射相關的方法:

(1)基本套路this.Has(p=>p.A).With***() 當前這個表和A 屬性的表的關系是Has 定義, With 定義的是A 對應的表和這個表的關系。Optional/Required/Many

(2)HasOptional() 有一個可選的(可以為空的)

(3)HasRequired() 有一個必須的(不能為空的)

(4)HasMany() 有很多的

(5)WithOptional() 可選的

(6)WithRequired() 必須的

(7)WithMany() 很多的

舉例:

在AAA 實體中配置this.HasRequired(p=>p.BBB).WithMany();是什么意思? 在AAA 實體中配置this.HasRequired(p=>p.BBB).WithRequired ();是什么意思?

配置一對多關系

(1)先按照正常的單表配置把Student、Class 配置起來,T_Students 的ClassId 字段就對應Student類的ClassId 屬性。WithOptional()

using (MyDbContext ctx = new MyDbContext ())

{

Class c l = new Class { Name= " 三年二班,, } ;

ctx. Cl asses. Add (cl) ;

ctx. SaveChanges () ;

Student s l = new Student { Age = 11, Nam e = " 張三" , Cl assl d = cl. Id } ;

Student s2 = new Student { Name = " 李四" , Classld = cl. Id } ;

ctx.Students.Add(s1);

ctx. Students. Add(s2);

ctx. SaveChanges O ;

}

(2)給Student類增加一個Class類型、名字為Class(不一定非叫這個,但是習慣是:外鍵名去掉Id)的屬性,要聲明成virtual(后面講原因)。

(3)然后就可以實現各種對象間操作了:

Console.WriteLine(ctx.Students.First().Class.Name)

然后數據插入也變得簡單了,不用再考慮“先保存Class,生成Id,再保存Student”了。這樣就是純正的“面向對象模型”,ClassId 屬性可以刪掉。

Class c1 = new Class { Name = "五年三班" };

ctx.Classes.Add(c1);

Student s1 = new Student { Age = 11, Name = "皮皮蝦"};

Student s2 = new Student { Name = "巴斯"};

s1.Class = c1;

s2.Class = c1;

ctx.Students.Add(s1);

ctx.Students.Add(s2);

ctx.Classes.Add(c1);

ctx.SaveChanges();

(4)如果ClassId 字段可空怎么辦?直接把ClassId 屬性設置為long?

(5)還可以在Class中配置一個public virtual ICollection Students { get; set; } = new List(); 屬性。最好給這個屬性初始化一個對象。注意是virtual。這樣就可以獲得所有指向了當前對象的Stuent 集合,也就是這個班級的所有學生。我個人不喜歡這個屬性,業界的大佬也是建議“盡量不要設計雙向關系”,因為可以通過Class clz = ctx.Classes.First(); var students =ctx.Students.Where(s => s.ClassId == clz.Id);來查詢獲取到,思路更清晰。

不過有了這樣的集合屬性之后一個方便的地方:

Class c1 = new Class { Name = "五年三班" };

ctx.Classes.Add(c1);

Student s1 = new Student { Age = 11, Name = "皮皮蝦" };

Student s2 = new Student { Name = "巴斯" };

c1.Students.Add(s1);//注意要在Students屬性聲明的時候= new List();或者在之前賦值

c1.Students.Add(s2);

ctx.Classes.Add(c1);

ctx.SaveChanges();

EF會自動追蹤對象的關聯關系,給那些有關聯的對象也自動進行處理。

在進行數據遍歷的時候可能會報錯“已有打開的與此 Command 相關聯的 DataReader,必須首先將它關閉。”

foreach(var s in ctx.Students)

{

Console.WriteLine(s.Name);

Console.WriteLine(s.Class.Name);

}

一對多深入:

默認約定配置即可,如果非要配置,可以在StudentConfig 中如下配置:

this.HasRequired(s=> s.Class).WithMany().HasForeignKey(s => s.ClassId);

表示“我需要(Require)一個Class,Class有很多(Many)的Student;ClassId是這樣一個外鍵”。

如果ClassId 可空,那么就要寫成:

this.HasOptional (s => s.Class).WithMany().HasForeignKey(s => s.ClassId);

如果這樣Class clz = ctx.Classes.First();foreach (Student s in clz.Students)訪問,也就是從一端發起對多端的方法,那么就會報錯“找不到Class_Id 字段”需要在ClassConfig中再反向配置一遍 HasMany(e =>e.Students).WithRequired().HasForeignKey(e=>e.ClassId); 因為如果在Class 中引入Students 屬性,還要再在ClassConfig 再配置一遍反向關系,很麻煩。因此再次驗證“不要設計雙向關系”。

如果一張表中有兩個指向另外一個表的外鍵怎么辦?比如學生有“正常班級Class”(不能空)和“小灶班級XZClass”(可以空)兩個班。在StudentConfig 中:

this.HasRequired(s => s.Class).WithMany().HasForeignKey(s => s.ClassId);

this. HasOptional (s => s.XZClass).WithMany().HasForeignKey(s => s.XZClassId);

多對多關系配置

老師和學生:

class Student

{

public long Id { set; get; }

public string Name { get; set; }

public virtual ICollectionTeachers { get; set; }=new List();

}

class Teacher

{

public long Id { set; get; }

public string Name { get; set; }

public virtual ICollectionStudents { get; set; }=new List< Student >();

}

class StudentConfig : EntityTypeConfiguration{

public StudentConfig()

{

ToTable("T_Students");

}

}

class TeacherConfig : EntityTypeConfiguration{

public TeacherConfig()

{

ToTable("T_Teachers");

this.HasMany(e => e.Students).WithMany(e => e.Teachers)//易錯,容易丟了WithMany 的參數

.Map(m =>

m.ToTable("T_TeacherStudentRelations").MapLeftKey("TeacherId").MapRightKey("StudentId"));

}

}

關系配置到任何一方都可以

這樣不用中間表建實體(也可以為中間表建立一個實體,其實思路更清晰),就可以完成多對多映射。當然如果中間關系表還想有其他字段,則要必須為中間表建立實體類。 測試:

Teacher t1 = new Teacher();

t1.Name = "張老師";

t1.Students = new List();

Teacher t2 = new Teacher();

t2.Name = "王老師";

t2.Students = new List();

Student s1 = new Student();

s1.Name = "tom";

s1.Teachers = new List();

Student s2 = new Student();

s2.Name = "jerry";

s2.Teachers = new List();

t1.Students.Add(s1);

附錄:

(1)關于WithMany()的參數

在一對多關系中,如果只配置多端關系并且沒有給WithMany()指定參數的話,在進行反向關系操作的時候就會報錯。要么在一端也配置一次,最好的方法就是還是只配置多端,只不過給WithMany()指定參數:

class StudentConfig:EntityTypeConfiguration{

public StudentConfig()

{

ToTable("T_Students");

this.HasRequired(e => e.Class).WithMany(e=>e.Students)

.HasForeignKey(e=>e.ClassId);

}

}

當然還是不建議用反向的集合屬性,如果Class沒有Students這個集合屬性的話,就不用(也不能)WithMany的參數了。

關于多對多關系配置的WithMany()問題

上次講配置多對多的關系沒有給WithMany設定參數,這樣反向操作的時候就會出錯,應該改成:this.HasMany(e => e.Students).WithMany(e=>e.Teachers)

總結:一對多的中不建議配置一端的集合屬性,因此配置的時候不用給WithMany()參數,如果配置了集合屬性,則必須給WithMany 參數;多對多關系必須要給WithMany()參數。

總結一對多、多對多的“最佳實踐”

(2)一對多最佳方法(不配置一端的集合屬性):

多端

public class Student

{

public long Id { get; set; }

public string Name { get; set; }

public long ClassId { get; set; }

public virtual Class Class { get; set; }

}

一端

public class Class

{

public long Id { get; set; }

public string Name { get; set; }

}

在多端的模型配置(StudentConfig)中:

this.HasRequired(e => e.Class).WithMany() .HasForeignKey(e=>e.ClassId);

(3)一對多的配置(在一端配置一個集合屬性,極端不推薦)

多端

public class Student

{

public long Id { get; set; }

public string Name { get; set; }

public long ClassId { get; set; }

public virtual Class Class { get; set; }

}

一端

public class Class

{

public long Id { get; set; }

public string Name { get; set; }

public virtual ICollectionStudents { get; set; } = new List();

}

多端的配置(StudentConfig)中

this.HasRequired(e => e.Class).WithMany(e=>e.Students)//WithMany()的參數不能丟 .HasForeignKey(e=>e.ClassId);

(4)多對多最佳配置

兩端模型

public class Student

{

public long Id { get; set; }

public string Name { get; set; }

public virtual ICollectionTeachers { get; set; } = new List();

}

public class Teacher

{

public long Id { get; set; }

public string Name { get; set; }

public virtual ICollectionStudents { get; set; } = new List();

}

在其中一端配置(StudentConfig)

this.HasMany(e => e.Teachers).WithMany(e=>e.Students).Map(m =>//不要忘了WithMany的參數 m.ToTable("T_StudentTeachers").MapLeftKey("StudentId").MapRightKey("TeacherId"));

多對多中 移除關系:t.Students.Remove(t.Students.First()); 添加關系

()多對多中還可以為中間表建立一個實體方式映射。當然如果中間關系表還想有其他字段,則要必須為中間表建立實體類(中間表和兩個表之間就是兩個一對多的關系了)。

數據庫創建策略(): 如果數據庫創建好了再修改模型或者配置,運行就會報錯,那么就要手動刪除數據庫或者:Database.SetInitializer(new DropCreateDatabaseIfModelChanges());如果報錯“數據庫正在使用”,可能是因為開著Mangement Studio,先關掉就行了。知道就行了,只適合學習時候使用。

CodeFirst Migration 參考(*): http://www.cnblogs.com/libingql/p/3330880.html 太復雜, 不符合Simple is Best 的原則,這是為什么有一些開發者不用EF,而使用Dapper 的原因。

做項目的時候建議初期先把主要的類使用EF 自動生成表,然后干掉Migration 表,然后就 Database.SetInitializer(null);以后對數據庫表的修改都手動完成,也就是手動改實體類、 手動改數據庫表。

三丶 延遲加載(LazyLoad)

如果public virtual Class Class { get; set; }(實體之間的關聯屬性又叫做“導航屬性(Navigation Property)”)把virtual 去掉,那么下面的代碼就會報空引用異常

var s = ctx.Students.First();

Console.WriteLine(s.Class.Name);

聯想為什么?憑什么!!! 改成virtual觀察SQL的執行。執行了兩個SQL,先查詢T_Students,再到T_Classes中查到對應的行。 這叫“延遲加載”(LazyLoad),只有用到關聯的對象的數據,才會再去執行select 查詢。注意延遲加載只在關聯對象屬性上,普通屬性沒這個東西。 注意:啟用延遲加載需要配置如下兩個屬性(默認就是true,因此不需要去配置,只要別手賤設置為false 即可)

context.Configuration.ProxyCreationEnabled = true;

context.Configuration.LazyLoadingEnabled = true;

分析延遲加載的原理:打印一下拿到的對象的GetType(),再打印一下GetType().BaseType;我們發現拿到的對象其實是Student子類的對象。(如果和我這里結果不一致的話,說明:類不是public,沒有關聯的virtual 屬性) 因此EF其實是動態生成了實體類對象的子類,然后override了這些virtual屬性,類似于這樣的 實現:

public class StudentProxy:Student

{

private Class clz;

public override Class Class

{

get

{

if(this.clz==null)

{

this.clz= ....//這里是從數據庫中加載Class 對象的代碼

}

return this.clz;

}

}

}

再次強調:如果要使用延遲加載,類必須是public,關聯屬性必須是virtual。 延遲加載(LazyLoad)的優點:用到的時候才加載,沒用到的時候才加載,因此避免了一次性加載所有數據,提高了加載的速度。缺點:如果不用延遲加載,就可以一次數據庫查詢就可以把所有數據都取出來(使用join實現),用了延遲加載就要多次執行數據庫操作,提高了數據庫服務器的壓力。 因此:如果關聯的屬性幾乎都要讀取到,那么就不要用延遲加載;如果關聯的屬性只有較小的概率(比如年齡大于7 歲的學生顯示班級名字,否則就不顯示)則可以啟用延遲加載。這個概率到底是多少是沒有一個固定的值,和數據、業務、技術架構的特點都有關系,這是需要經驗和直覺,也需要測試和平衡的。 注意:啟用延遲加載的時候拿到的對象是動態生成類的對象,是不可序列化的,因此不能直接放到進程外Session、Redis 等中,解決方法?

(一) 不延遲加載,怎么樣一次性加

用EF永遠都要把導航屬性設置為virtual。又想方便(必須是virtual)又想效率高!

使用Include()方法:

var s = ctx.Students.Include("Class").First();

觀察生成的SQL語句,會發現只執行一個使用join的SQL就把所有用到的數據取出來了。當然拿到的對象還是Student 的子類對象,但是不會延遲加載。(不用研究“怎么讓他返回Student 對象”)

Include(“Class”)的意思是直接加載Student 的Class 屬性的數據。注意只有關聯的對象屬性才可以用Include,普通字段不可以直接寫"Class"可能拼寫錯誤,如果用C#6.0,可以使用nameof語法解決問這個問題:

var s = ctx.Students.Include(nameof(Student.Class)).First();

也可以using System.Data.Entity;然后var s = ctx.Students.Include(e=>e.Class).First(); 推薦這種做法。 如果有多個屬性需要一次性加載,也可以寫多個Include:

var s = ctx.Students.Include(e=>e.Class) .Include(e=>e.Teacher).First();

如果Class對象還有一個School屬性,也想把School對象的屬性也加載,就要:

var s = ctx.Students.Include("Class").Include("Class. School").First(); 或者更好的

var s = ctx.Students.Include(nameof(Student.Class)).Include(nameof(Student.Class)+"."+nameof(Class.School)).First();

(二) 延遲加載的一些坑

DbContext銷毀后就不能再延遲加載了,因為數據庫連接已經斷開

下面的代碼最后一行會報錯:

Student s;

using (MyDbContext ctx = new MyDbContext())

{

s = ctx.Students.First();

}

Console.WriteLine(s.Class.Name);

兩種解決方法:

用Include,不延遲加載(推薦)

Student s;

using (MyDbContext ctx = new MyDbContext())

{

s = ctx.Students.Include(t=>t.Class).First();

}

Console.WriteLine(s.Class.Name);

關閉前把要用到的數據取出來

Class c;

using (MyDbContext ctx = new MyDbContext())

{

Student s = ctx.Students.Include(t=>t.Class).First();\

c = s.Class;

}

Console.WriteLine(c.Name);

(2)兩個取數據一起使用

下面的程序會報錯:已有打開的與此 Command 相關聯的 DataReader,必須首先將它關閉。

foreach(var s in ctx.Students)

{

Console.WriteLine(s.Name);

Console.WriteLine(s.Class.Name);

}

(3)因為EF的查詢是“延遲執行”的,只有遍歷結果集的時候才執行select 查詢,而由于延遲加載的存在到s.Class.Name也會再次執行查詢。ADO.Net中默認是不能同時遍歷兩個DataReader。因此就報錯。

解決方法有如下

允許多個DataReader 一起執行:在連接字符串上加上MultipleActiveResultSets=true,但只適用于SQL 2005以后的版本。其他數據庫不支持。

執行一下ToList(),因為ToList()就遍歷然后生成List:

foreach(var s in ctx.Students.ToList())

{

Console.WriteLine(s.Name);

Console.WriteLine(s.Class.Name);

}

推薦做法:用Include預先加載:

foreach(var s in ctx.Students.Include(e=>e.Class))

{

Console.WriteLine(s.Name);

Console.WriteLine(s.Class.Name);

}

四丶 實體類的繼承

所有實體類都會有一些公共屬性,可以把這些屬性定義到一個父類中。比如:

public abstract class BaseEntity

{

public long Id { get; set; } //主鍵

public bool IsDeleted { get; set; } = false; //軟刪除

public DateTime CreateDateTime { get; set; } = DateTime.Now;//創建時間

public DateTime DeleteDateTime { get; set; } //刪除時間

}

使用公共父類的好處不僅是寫實體類簡單了,而且可以提供一個公共的Entity 操作類:

public abstract class BaseEntity

{

public long Id { get; set; } //主鍵

public bool IsDeleted { get; set; } = false; //軟刪除

public DateTime CreateDateTime { get; set; } = DateTime.Now;//創建時間

public DateTime DeleteDateTime { get; set; } //刪除時間

}

使用公共父類的好處不僅是寫實體類簡單了,而且可以提供一個公共的Entity 操作類:

class BaseDAOwhere T:BaseEntity

{

private MyDbContext ctx;//不自己維護MyDbContext 而是由調用者傳遞,因為調用者可以要執行很多操作,由調用者決定什么時候銷毀。

public BaseDAO (MyDbContext ctx)

{

this.ctx = ctx;

}

public IQueryableGetAll()//獲得所有數據(不要軟刪除的)

{

return ctx.Set().Where(t=>t.IsDeleted==false);//這樣自動處理軟刪除,避免了忘了過濾軟刪除的數據

}

public IQueryableGetAll(int start,int count) //分頁獲得所有數據(不要軟刪除的)

{

return GetAll().Skip(start).Take(count);

}

public long GetTotalCount()//獲取所有數據的條數

{

return GetAll().LongCount();

}

public T GetById(long id)//根據id 獲取

{

return GetAll().Where(t=>t.Id==id).SingleOrDefault();

}

public void MarkDeleted(long id)//軟刪除

{

T en = GetById(id);

if(en!=null)

{

en.IsDeleted = true;

en.DeleteDateTime = DateTime.Now;

ctx.SaveChanges();

}

}

}

DAL同層內返回IQueryable比IEnumerable更好

下面的代碼會報錯:

using (MyDbContext ctx = new MyDbContext())

{

BaseDAOdao = new BaseDAO(ctx);

foreach(var s in dao.GetAll())

{

Console.WriteLine(s.Name);

Console.WriteLine(s.Class.Name);

}

}

原因是什么?怎么Include?需要using System.Data.Entity;

using (MyDbContext ctx = new MyDbContext())

{

BaseDAOdao = new BaseDAO(ctx);

foreach(var s in dao.GetAll().Include(t=>t.Class))

{

Console.WriteLine(s.Name);

Console.WriteLine(s.Class.Name);

}

}

有兩個版本的Include、AsNoTracking:

(1)DbQuery 中的:DbQuery AsNoTracking()、DbQuery Include(string path)

(2)QueryableExtensions 中的擴展方法: AsNoTracking(this IQueryable source) 、 Include(this IQueryable source, string path)、Include(this IQueryablesource, Expression> path)

DbSet繼承自DbQuery;

Where()、Order、Skip()等這些方法返回的是IQueryable接口。

因此如果在IQueryable接口類型的對象上調用Include、AsNoTracking就要using System.Data.Entity

五丶 linq

(一) 簡介

查詢Id>1的狗有如下兩種寫法:

var r1 = dogs.Where(d => d.Id > 1);

var r2 = from d in dogs where d.Id>1 select d;

第一種寫法是使用lambda 的方式寫的,官方沒有正式的叫法,我們就叫“lambda寫法”;

第二種是使用一種叫Linq(讀作:link)的寫法,是微軟發明的一種類似SQL的語法,給我們一個新選擇。兩種方法是可以互相替代的,沒有哪個好、哪個壞,看個人習慣。

我的經驗:需要join等復雜用法的時候Linq更易懂,一般的時候“lambda寫法”更清晰,更緊湊。反編譯得知,這兩種寫法最終編譯成同樣的東西,所以本質上一樣的。

(二) 辟謠

“Linq被淘汰了”是錯誤的說法,應該是“Linq2SQL被淘汰了”。linq就是微軟發明的這個語法,可以用這種語法操作很多數據,操作SQL數據就是Linq2SQL,linq操作后面學的EntityFramework就是Linq2Entity,linq操作普通.Net 對象就是Linq2Object、Linq操作XML文檔就是Linq2XML。

(三) Linq 基本語法

以from item in items 開始,items為待處理的集合,item為每一項的變量名;最后要加上select,表示結果的數據;記得select一定要最后。這是剛用比較別扭的地方。

看各種用法,不用解析:

var r= from d in dogs select d.Id;

var r= from d in dogs select new{d.Id,d.Name,Desc="一條狗"};

排序

var items = from d in dogs

//orderby d.Age

//orderby d.Age descending

orderby d.Age,d.MasterId descending

select d;

join

var r9 = from d in dogs

join m in masters on d.MasterId equals m1.Id

select new { DogName=d.Name,MasterName=m.Name};

注意join中相等不要用==,要用equals。寫join的時候linq比“lambda”漂亮

group by

var r1 = from p in list

group p by p.Age into g

select new { Age = g.Key, MaxSalary = g.Max(p=>p.Salary), Count = g.Count() };

(四) 混用

只有Where,Select,OrderBy,GroupBy,Join 等這些能用linq寫法,如果要用下面的 “Max,Min,Count,Average,Sum,Any,First,FirstOrDefault,Single,SingleOrDefault,Distinct,Skip,Take等”則還要用lambda 的寫法(因為編譯后是同一個東西,所以當然可以混用)。

var r1 = from p in list

group p by p.Age into g

select new { Age = g.Key, MaxSalary = g.Max(p=>p.Salary), Count = g.Count() };

int c = r1.Count();

var item = r1.SingleOrDefault();

var c = (from p in list

where p.Age>3

select p

).Count();

lambda對linq說:論漂亮我不行,論強大你不行!

六丶C#6.0 語法

(1)屬性的初始化“public int Age{get;set;}=6”。低版本.Net中怎么辦?

(2)nameof:可以直接獲得變量、屬性、方法等的名字的字符串表現形式。獲取的是最后一段的名稱。如果在低版本中怎么辦?

class Program

{

static void Main(string[] args)

{

Person p1 = new Person();

string s1 = nameof(p1);

string s2 = nameof(Person);

string s3 = nameof(p1.Age);

string s4 = nameof(Person.Age);

string s5 = nameof(p1.F1);

Console.ReadKey();

}

}

public class Person

{

public int Age { get; set; }

public string Name { get; set; }

public void Hello()

{

}

public static void F1()

{

}

}

好處:避免寫錯了,可以利用編譯時檢查。

應用案例:ASP.Net MVC 中的[Compare(“BirthDay”)]改成[Compare(nameof(BirthDay))]

(3)??語法:int j= i??3; 如果i為null則表達式的值為3,否則表達式的值就是i的值。如果在低版本中怎么辦?int j = (i== null)?3:(int)i;

應用案例:string name = null;Console.WriteLine(name??“未知”);

(4)?.語法:string s8 = null;string s9 = s8?.Trim(); 如果s8為null,則不執行Trim(),讓表達式的結果為null。在低版本中怎么辦?

string s9=null;if(s8!=null){s9=s8.Trim();};

七丶ORM

(一)ORM簡介

ORM(Object Relational Mapping)對象關系映射,一般指持久化數據和實體對象的映射

數據存儲是絕大多數軟件系統都要接觸到的技術,具有一定規模的軟件產品,為了方便存儲和管理數據,便引入了數據庫這一工具,但是數據如何從程序寫入數據庫的呢?

為方便程序員通過代碼將數據寫入數據庫,一般的語言開發的廠商都會為各種數據庫適配數據庫連接的驅動程序,比如ADO.Net,JDBC等。

但是數據庫連接的驅動程序的職責在于管理連接數據庫,設置連接參數等信息,通常會返回各自封裝好的數據集類型,驅動程序封裝的類型往往是以數據為核心進行描述的,現代化的軟件設計為了簡便描述事物的特征都而以面向對象思想為核心,兩者之間的轉換還有很多的路要走。

除卻轉換部分,Sql語句的編寫也是一大學問,一般的編程語言都沒有為sql語句定義類型,這是因為每種數據庫的sql語句風格都是不一樣的,難以給出一個統一的方案。退而求其次,一般的編程語言都采用字符串形式傳遞sql語句到數據庫驅動程序。拋棄各種各樣的sql語句的學習之外,這種方式有一個很大的弊端,那就是sql語句的拼寫極容易由于手誤而犯錯。

在這種場景下,ORM框架誕生了!

(二)ORM的工作原理

沒有ORM的情況下,主要有兩個槽點:

驅動返回類型和對象不能良好映射

SQL語句的學習成本及易錯率(多種數據庫語句難以全部掌握)

那么,且看我們的ORM如何改善這兩個槽點:

(1)數據驅動返回的數據通常都是以數據為核心的數據集合,我們需要通過手動將類對象和數據庫返回的列數據進行一一匹配獲取,然后賦值到對象上。在這里要感謝泛型和反射兩大語法,通過泛型和反射,我們可以獲取到任何實體類的屬性而不是具體到某一種類型,通過遍歷實體類的屬性去數據集合中一一獲取并復制返回。這一操作便將數據集合的數據完美包裝成了以面向對象為核心的和類相關的對象數據集合。

(2)sql語句的拼寫,我們可以提供一套公共sql語句模板,然后在具體實體對象操作的時候將實體對象的屬性名稱和屬性值當作參數拼接進去,組裝成完整的sql語句(例如java體系中的Mybatis框架)或者依舊采用封裝一套淺顯易懂的Api,Api內部通過對應方法和實體對象的組裝成sql語句(例如.Net體系中EntityFramework框架)

(3)最重要的兩個問題解決完之后,我們可以在框架中做一些對我們有幫助的其他事情。ORM框架做的最多的便是“緩存”。

作為程序員應該掌握的基礎知識,數據庫操作是要和硬盤打交道的,而程序是在內存中運行的,操作內存的速度要比操作硬盤快數十倍以上,可見一個訪問量較高的大型系統很容易由于數據庫操作過于頻繁而拖慢整體速度,從而影響系統的使用。因此,ORM框架要幫助我們減少數據庫的訪問,加快系統速度。

ORM框架的緩存系統一般是較為復雜的,而且每種ORM框架對緩存的實現機制都是不同的。整體的思路卻是一致的,對訪問頻率較高的數據進行緩存,并在對數據編輯的時候要對緩存進行更新,以免出現數據不一致的問題。詳細的緩存實現策略這里不一一贅述,感興趣可以針對某個ORM框架進行剖析。

(三)ORM的優缺點

優點:

(1)ORM框架降低了學習門檻,一個對sql語句并不熟悉的開發人員也可以很容易通過簡易的ORM框架Api進行數據庫的操作。

(2)提高了開發效率,ORM使我們減少很多繁瑣重復的工作量,讓我們的注意力集中在實現業務上。

(3)一定程度上提高了程序的響應速度。

弊端:

(1)框架會自動生成Sql語句,所有場景的sql語句都是同一套模板,難以自動針對場景對sql語句進行良好的優化,某種場景下很容易生成執行很慢的sql語句。如果讓DBA看到這樣的執行sql,必定引來抓狂崩潰。

(2)ORM框架只是為了滿足絕大多數的場景而生的,特殊需要優化sql的場景下,我們完全可以直接使用驅動手動執行sql或使用ORM框架內提供的sql語句api進行自定義sql語句。

總結

以上是生活随笔為你收集整理的sql注入pythonpoco_.NET EF(Entity Framework)详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

91伊人久久大香线蕉蜜芽人口 | 五月婷婷开心中文字幕 | 97精品国产97久久久久久久久久久久 | 成人久久久精品国产乱码一区二区 | 丁香婷婷久久久综合精品国产 | 久久精品视频在线免费观看 | 久草干 | 黄网站色视频免费观看 | 日韩有码在线播放 | www.色爱 | 国产精品久久综合 | 亚洲天堂免费视频 | 日韩欧美网站 | 久久激情久久 | 西西大胆免费视频 | 蜜臀久久99精品久久久无需会员 | 2019中文字幕网站 | 三级av小说| 国产麻豆成人传媒免费观看 | 六月天综合网 | 亚州人成在线播放 | 99色网站| 日韩精品久久久久久久电影99爱 | 国产日韩精品在线观看 | www.色爱| 日韩三级在线 | 狠狠地操| 美女视频黄,久久 | 狠狠天天 | 亚洲婷婷综合色高清在线 | 日韩v在线91成人自拍 | av大全在线播放 | 国产黄色在线看 | 国产aa免费视频 | 免费日韩视 | 欧美色噜噜 | 婷婷色社区 | 成人中文字幕在线 | 中文字幕一区在线观看视频 | 国产精品第 | 欧美激情视频免费看 | 国产精品久久久久久影院 | 少妇视频一区 | 国产成人av网站 | 亚洲欧美怡红院 | 欧美一级电影免费观看 | 免费观看成人 | 亚洲综合视频在线观看 | 天天干天天操天天搞 | 色噜噜在线观看视频 | 精选久久 | 毛片基地黄久久久久久天堂 | 狠狠色丁香久久婷婷综 | 中文字幕资源网 | 一二区精品 | 九九精品在线观看 | 日本久久久久久久久久 | 国产精品久久久久久999 | 五月天亚洲综合 | 国产免费一区二区三区最新6 | 在线视频区 | 最新国产精品亚洲 | 超碰在线公开免费 | 亚洲永久精品在线观看 | 99视频久久| 狠狠狠狠狠狠操 | 成人久久国产 | 久久人人爽人人爽人人片av软件 | 日本丶国产丶欧美色综合 | 在线观看国产www | 国产美女久久 | 精品在线视频一区二区三区 | 久精品视频在线 | 少妇自拍av | 四川bbb搡bbb爽爽视频 | 久久影院午夜论 | 一区二区三区精品久久久 | 久久成年人网站 | 在线观看亚洲电影 | 国产香蕉视频在线观看 | 久久视频免费在线 | 黄色毛片视频免费观看中文 | 91av在线不卡 | 婷婷色伊人 | 麻豆免费视频网站 | 成人视屏免费看 | 国产美女视频网站 | 韩日视频在线 | 国产免费一区二区三区网站免费 | 国产免费av一区二区三区 | 久草在线在线视频 | 国产片免费在线观看视频 | 波多野结衣理论片 | 欧美色综合| 天天操天天吃 | 亚洲精品午夜国产va久久成人 | 一区二区三区在线视频观看58 | 久久久综合香蕉尹人综合网 | 激情久久综合 | 日韩精品一区电影 | 亚洲综合在线播放 | 日韩激情片在线观看 | 在线观看片 | 免费视频黄色 | 亚洲一区网| 人人讲下载| 日本在线中文在线 | 久久天天躁夜夜躁狠狠躁2022 | 亚洲视频1区2区 | 日韩高清不卡一区二区三区 | 中文字幕频道 | 久久久久久久久久久免费视频 | 456成人精品影院 | 中文字幕高清视频 | 成人一区电影 | 精品久久毛片 | 操久在线| 日日日视频 | 色婷婷a| 狠狠撸电影 | 久久精品人 | 日韩高清在线一区二区 | 久久久久久久99精品免费观看 | 欧美一区免费在线观看 | 成人动漫精品一区二区 | 国产一级免费在线 | 国产精品美女久久久久久2018 | 国产精久久久久久妇女av | 亚洲九九九 | 午夜精品影院 | 欧美性大胆 | 四虎在线观看 | 91av久久 | 午夜影院一级片 | 国产五码一区 | 免费h漫在线观看 | 亚洲色图激情文学 | 久久国产成人午夜av影院宅 | 国产高清视频在线免费观看 | 91色九色 | 日韩黄在线观看 | 成人a免费视频 | 人人澡人人模 | 成人精品影视 | 不卡视频国产 | 日本在线观看视频一区 | 91福利视频网站 | 麻豆一级视频 | 国产一区二区精品91 | 一区二区三区久久 | 91c网站色版视频 | 日本爽妇网 | 国产福利一区二区在线 | 久草久草在线观看 | 亚洲精品自在在线观看 | 在线观看的av | 视频在线观看入口黄最新永久免费国产 | 成人免费看片网址 | 久久久久国产精品一区二区 | www.99热精品| a级成人毛片 | 最新真实国产在线视频 | 91av电影在线观看 | 久草在线视频在线观看 | 狠狠五月婷婷 | 91网站免费观看 | 在线视频 国产 日韩 | 五月婷在线 | 日韩欧美在线视频一区二区三区 | 91黄在线看 | 中文字幕在线影视资源 | 一级精品视频在线观看宜春院 | 日韩久久视频 | 日本女人在线观看 | 99r精品视频在线观看 | 黄色91免费观看 | 色在线视频 | 中文字幕免费高 | 午夜久久久久久久久久久 | 国际精品久久 | 亚洲高清精品在线 | 亚洲黄色app | 在线观看成年人 | 亚洲精品在线观看av | 久久精品国产免费看久久精品 | 久久综合九色综合欧美就去吻 | 91看成人| 网站免费黄| 狠狠色噜噜狠狠狠合久 | 五月婷婷在线播放 | 午夜久久成人 | 午夜少妇一区二区三区 | 中字幕视频在线永久在线观看免费 | 日韩中文字幕国产精品 | 日韩欧美精品在线观看视频 | 欧美日韩国产精品一区 | 国产日产av | 麻豆成人在线观看 | 女人18毛片90分钟 | 在线观看的av网站 | 99视频国产精品免费观看 | 日韩激情视频在线观看 | 午夜a区 | 久久99热久久99精品 | 99久久精品日本一区二区免费 | 不卡中文字幕av | 亚洲国产中文字幕在线视频综合 | 激情开心站 | 91探花视频 | 成人国产精品久久久久久亚洲 | 国产一区欧美日韩 | 亚洲精品乱码久久久久久按摩 | 中文字幕第一 | 在线成人观看 | 天天爱天天操天天射 | 天堂在线一区二区 | 久久免费电影网 | 久久开心激情 | 欧美在线一二 | 五月天激情开心 | 天天操天天拍 | 亚洲婷婷免费 | 四虎国产 | 懂色av懂色av粉嫩av分享吧 | 在线精品视频免费观看 | 伊人婷婷在线 | 日日草视频 | 国产乱码精品一区二区三区介绍 | 91精品国产福利在线观看 | 国产精品美乳一区二区免费 | 最新精品视频在线 | av在线看片 | 人人狠狠综合久久亚洲婷 | 国产精品欧美久久久久无广告 | 中文字幕在线观看完整版 | 日本视频久久久 | www激情久久 | 国产精品色婷婷 | 91探花国产综合在线精品 | 黄色三级网站 | 麻豆久久久久久久 | 中文字幕成人在线观看 | 五月综合激情婷婷 | 99精品视频一区 | 五月色丁香 | 日韩在线电影观看 | 国产精品久久久久久久久蜜臀 | 国产午夜小视频 | 国产又粗又猛又黄又爽的视频 | 亚洲午夜精品久久久 | 免费人成网 | 国产精品久久久久aaaa九色 | 国产成人免费在线观看 | 日韩在线视频不卡 | 国产在线观看网站 | 免费亚洲精品 | 激情五月网站 | 91人人射 | 黄色片视频免费 | 中文字幕精品一区 | 在线影院中文字幕 | 国产精品久久久久久久久久久久午夜 | 国产不卡在线 | 国产精品一区二区三区电影 | 久久久久久久久久伊人 | 91视频高清 | 精品成人免费 | 波多野结衣精品视频 | 免费观看性生交大片3 | www.888.av | 久久国产精品99久久久久久老狼 | 色综合天天色 | 久久国产精品色av免费看 | 亚欧日韩av | 精品美女久久久久久免费 | 久久草在线视频国产 | 精品国产电影一区 | 国产亚洲精品久久19p | 97国产 | 亚洲天堂网站视频 | 1024手机在线看 | 久久婷婷一区二区三区 | 国产亚洲精品久久 | 欧美精品二区 | 国产成人免费av电影 | a黄色片 | 午夜成人免费电影 | 久久99操| 日韩欧美在线播放 | 日韩一级精品 | 美女一级毛片视频 | 五月天婷婷在线播放 | 91精品久久久久久久久久入口 | 久久久国产影院 | 高清日韩一区二区 | 96亚洲精品久久久蜜桃 | 色综合激情久久 | a精品视频| 成人免费视频网址 | 在线免费观看国产视频 | 国产999精品久久久影片官网 | 婷婷色综合 | 日韩黄色在线观看 | 麻豆视频在线免费观看 | 成人免费在线播放视频 | 久久久久久久久福利 | 亚洲综合成人婷婷小说 | 国产精品视频永久免费播放 | 区一区二区三区中文字幕 | 日韩成人免费在线观看 | 激情动态 | 国产精品免费大片视频 | 开心丁香婷婷深爱五月 | 亚洲精品tv| 99视频精品视频高清免费 | 天天操夜夜操天天射 | 激情五月婷婷综合 | 国产日韩欧美在线播放 | 色欲综合视频天天天 | 九九激情视频 | 欧美国产大片 | 国产剧情久久 | 成人91视频 | 婷婷久久综合网 | 一本大道久久精品懂色aⅴ 五月婷社区 | 成人av在线看 | 日本少妇视频 | 亚洲另类人人澡 | 一区国产精品 | 国产做a爱一级久久 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 国产一二区免费视频 | 亚洲精品在 | 日韩久久午夜一级啪啪 | 三级黄色片子 | 欧美国产日韩在线视频 | 91九色成人蝌蚪首页 | 91中文字幕网 | 国产分类视频 | 夜夜操天天操 | 狠狠狠色丁香综合久久天下网 | 国产黄色片久久 | 国产精品第一页在线观看 | 国产日产欧美在线观看 | av免费高清观看 | 婷婷av电影 | 色噜噜日韩精品欧美一区二区 | 看片的网址 | 88av视频| 亚洲综合在线五月天 | 麻豆成人在线观看 | 久久久久伊人 | 99在线视频观看 | 欧美日韩一区二区三区不卡 | 欧美成a人片在线观看久 | 人人搞人人搞 | 99视频在线精品国自产拍免费观看 | 日韩深夜在线观看 | 国产精品成人av在线 | 国产成人精品久久久 | 国产69熟 | 国产成人精品一二三区 | 99精品视频免费看 | 久草国产在线观看 | 久久久久草 | 四虎国产精品免费观看视频优播 | 91av播放| 欧美天天干 | 午夜久久网站 | 中文字幕在线观看第一页 | www.在线观看视频 | 久久美女精品 | 日韩欧美大片免费观看 | 久久精品国产一区 | 国产午夜精品一区二区三区欧美 | 伊人影院在线观看 | 精品资源在线 | 超碰97公开 | 欧美一级特黄aaaaaa大片在线观看 | av在线一二三区 | 欧美日韩a视频 | 久久在线视频在线 | 香蕉在线播放 | 国产精品久久av | 91大神一区二区三区 | 久久精品美女视频 | 婷婷在线色| 天天爱综合 | 成人性生交大片免费看中文网站 | 久久午夜免费观看 | 天天干夜夜想 | 欧美在线视频一区二区三区 | 手机在线永久免费观看av片 | 亚洲成人av片 | 国产精品国产三级国产aⅴ入口 | 精品视频专区 | 韩国在线一区二区 | 成人av一二三区 | 久久人人爽人人爽人人 | 一级做a爱片性色毛片www | 欧美一级片| 国产天天综合 | 国内精品中文字幕 | 国产成人久久精品一区二区三区 | 久久久这里有精品 | 去干成人网 | 中文字幕一区二区三区在线观看 | 人九九精品 | 97超碰人人澡人人 | 国产精品午夜在线观看 | 国产成人中文字幕 | 麻豆免费视频网站 | 97超碰国产在线 | 久久精品久久精品 | 天天操天天干天天爱 | 国产精品免费久久久久久久久久中文 | 麻豆成人精品 | 欧美一区二区三区激情视频 | 国产精品你懂的在线观看 | 国产精品一区二区三区四区在线观看 | 五月婷婷操| 国内亚洲精品 | 色激情五月 | 久久人人看 | 亚洲成a人片在线观看网站口工 | 欧美 日韩 国产 成人 在线 | 亚洲91在线| 中文字幕2021 | 男女男视频 | 五月婷av| 免费特级黄毛片 | 国产专区视频在线 | 黄色av影院| 果冻av在线| 日韩视频一区二区在线观看 | 午夜久久成人 | 久久久久免费精品视频 | www.色综合.com| 欧美色黄 | 久久精品999 | 日韩黄色在线电影 | 在线视频婷婷 | 亚洲在线激情 | 久久免费播放 | 国产区在线 | 在线视频你懂得 | 欧美韩国日本在线 | 国产亚洲精品美女 | 欧美精品久久久久久久久久白贞 | 人人爽人人爱 | 久久久久这里只有精品 | 国产精品毛片久久久久久久久久99999999 | 夜夜操天天操 | 精品av在线播放 | 国产成人一区二区三区在线观看 | 久久在线视频精品 | 97精品久久 | 国产黄在线播放 | 欧美精品久久久久久久免费 | 久久香蕉电影网 | 天天碰天天操视频 | 干狠狠 | 国产高清专区 | 久免费 | www.色就是色 | 99在线观看视频 | 国产黄在线免费观看 | 激情欧美xxxx | 久久伊人免费视频 | 伊人干综合 | 日韩欧美精品一区二区三区经典 | 久久国产免费 | 欧美福利久久 | 人人射| 国产一区电影在线观看 | 黄色的视频 | 久久精品视频在线免费观看 | 免费视频久久久 | 国产资源 | 免费网站观看www在线观看 | 久久久五月婷婷 | 美女久久久久久久 | 国产麻豆精品免费视频 | 96亚洲精品久久 | 玖操| 香蕉久久久久久久 | 日日干美女 | 精品国产一区二区三区久久久蜜臀 | 国产精品a成v人在线播放 | 在线观看黄色国产 | av官网在线| 久久人人爽人人 | 成人av在线播放网站 | 国内精品久久久久久久久 | 91网在线观看| 国产一级在线观看视频 | 欧美黄在线 | 国产v亚洲v| 国产精品国产三级国产aⅴ9色 | 亚洲女欲精品久久久久久久18 | 亚洲精品h | 99久久精品一区二区成人 | 992tv在线 | 欧美另类高潮 | 国产精品久一 | 在线成人免费电影 | 天天操天天射天天 | 国产一级免费播放 | 91视频观看免费 | 欧美激情va永久在线播放 | 五月开心网 | 玖草在线观看 | 久久久久亚洲最大xxxx | 亚洲综合激情小说 | 天天干天天色2020 | 午夜.dj高清免费观看视频 | 日韩av电影免费在线观看 | 久久视频精品在线观看 | 99精品久久久久久久久久综合 | 又黄又爽又无遮挡免费的网站 | 久久xx视频| 久久伦理电影网 | 免费男女羞羞的视频网站中文字幕 | 久久综合色婷婷 | 中文字幕乱偷在线 | 五月激情姐姐 | 国产午夜在线观看 | 亚洲精品视频第一页 | 久久久久久久久久久久国产精品 | 精品福利网站 | 国内成人精品2018免费看 | 亚洲欧洲精品一区二区精品久久久 | 国产精品国产三级国产不产一地 | 91在线一区二区 | 国产成人性色生活片 | 亚洲日本欧美在线 | 亚洲国内精品在线 | 黄色片视频在线观看 | 久久福利影视 | 日日夜夜操操操操 | 中文av在线天堂 | 国产成人久久精品77777综合 | 亚洲天堂网视频在线观看 | 久久桃花网 | 99热这里精品 | 国产精品久久中文字幕 | 天天干天天插 | 天天操天天色天天射 | 综合网色| 久久99网站| 丁香久久婷婷 | 国产日产精品久久久久快鸭 | 在线免费色视频 | 国产一区二区三精品久久久无广告 | 国产区久久 | 欧美亚洲精品一区 | 久久综合9988久久爱 | 国产精品久久久久久久久久久久久 | 日韩女同一区二区三区在线观看 | 九九免费在线看完整版 | www久久九| 黄色成人影视 | 国产69精品久久久久99 | 狠狠天天 | 国产二区精品 | 久久精品三| 久久久久久高清 | 成人在线免费看视频 | 夜夜骑首页 | 黄色精品网站 | 一区二区中文字幕在线观看 | 成人黄色av免费在线观看 | 国产精品视频内 | 在线91精品 | 国产1级毛片| 日韩欧美视频在线观看免费 | 黄色在线观看污 | 欧美成人999 | 日本激情中文字幕 | 91精品久久久久久久久久入口 | 日日夜夜天天久久 | 精品国产人成亚洲区 | 久久免费成人精品视频 | 午夜三级理论 | 五月婷婷在线视频观看 | 日韩精品最新在线观看 | 91九色国产在线 | 99久久综合狠狠综合久久 | 欧美一性一交一乱 | 亚洲第二色| 亚洲欧美激情精品一区二区 | 中文字幕在线观看一区 | 蜜臀精品久久久久久蜜臀 | 精品久久一级片 | 亚洲精品xxxx | 99热国产在线中文 | 欧美色图一区 | 成人高清av在线 | 精品视频国产一区 | www.av免费观看 | 91视频网址入口 | 日韩综合视频在线观看 | 日日爱网址 | 天天色影院 | 岛国精品一区二区 | 亚洲美女久久 | 精品欧美一区二区精品久久 | 日韩最新av在线 | 国产人免费人成免费视频 | 香蕉久草 | 婷婷丁香六月 | 日韩在线观看一区二区 | 欧洲精品视频一区 | 国产午夜一区二区 | 狠狠的操你 | 成人中文字幕在线观看 | 中文字幕国产视频 | 免费影视大全推荐 | 国产精品免费观看国产网曝瓜 | 欧美日韩成人一区 | 国产精品丝袜在线 | 中文综合在线 | 久免费视频 | 手机看国产毛片 | 91麻豆精品 | 成年人免费观看国产 | 成人91在线| 嫩嫩影院理论片 | 亚洲午夜精品在线观看 | 国产日韩欧美网站 | 欧美巨乳波霸 | 婷婷www | 亚洲人人爱 | 日夜夜精品视频 | 国产69精品久久久久99尤 | www.久久久 | 欧美大荫蒂xxx | 日韩 在线| 麻豆国产精品视频 | 亚洲春色综合另类校园电影 | 国产在线一区二区 | 日日夜夜精品视频天天综合网 | 91免费看片黄 | 天天碰天天操视频 | 制服丝袜一区二区 | 在线观看亚洲精品 | 日韩av线观看 | 日本成址在线观看 | 免费看搞黄视频网站 | 日韩 国产| 九色视频网 | 亚洲乱码精品久久久久 | 亚洲乱码精品久久久 | 久久久久99999| 亚洲午夜在线视频 | 91毛片在线观看 | 亚洲视频1区2区 | 国产老妇av | 顶级bbw搡bbbb搡bbbb | 狠狠狠狠狠操 | 91九色视频国产 | 成人羞羞视频在线观看免费 | 99精品视频免费 | 国产亚洲欧美在线视频 | 欧美久久久久 | 91免费看片黄| 深爱五月网 | 99久热在线精品 | 亚洲国产精品va在线看黑人 | 在线免费国产 | 欧美久草在线 | 草久在线观看视频 | 一级电影免费在线观看 | 久久一区二区三区超碰国产精品 | 91成人精品一区在线播放 | 久久久久久久久久毛片 | 国产精品久久久区三区天天噜 | 日韩在线视频观看免费 | 亚洲美女精品视频 | 国产麻豆精品一区 | 香蕉97视频观看在线观看 | 亚洲色五月 | 国产黄色精品在线观看 | 国产免费久久久久 | 1000部国产精品成人观看 | 国产精品av在线免费观看 | 91黄色免费网站 | 精品成人a区在线观看 | 国产成人久久精品一区二区三区 | 免费激情在线电影 | 日韩av五月天 | av黄色在线播放 | 九九免费在线观看 | 超碰人人av | 视频精品一区二区三区 | 一区二区三区高清不卡 | 亚洲aⅴ乱码精品成人区 | www五月天婷婷 | 欧美日韩国产综合一区二区 | 精品96久久久久久中文字幕无 | 1024手机基地在线观看 | 国产免费观看av | 最近中文字幕在线播放 | 久久久久久综合网天天 | 久久99久国产精品黄毛片入口 | 韩国一区二区三区在线观看 | 欧美日韩视频在线一区 | 免费观看十分钟 | 综合网伊人 | 久久精品一区二区三 | 久久综合九色综合97婷婷女人 | 黄色毛片视频免费观看中文 | 日韩.com| 精品国产精品久久 | 国产精品久久久久久av | 高清av不卡 | 成人国产亚洲 | 91麻豆精品国产午夜天堂 | 亚洲欧美精品在线 | 亚洲 欧洲 国产 精品 | 9999精品 | 免费黄色在线播放 | 日本女人的性生活视频 | 国产精品毛片一区二区在线看 | 最新三级在线 | 成人福利在线播放 | 久久久www成人免费精品张筱雨 | 国产区精品在线观看 | 狠狠地操 | 夜色.com | 五月婷婷丁香在线观看 | 999久久久欧美日韩黑人 | 91精彩在线视频 | 在线精品视频在线观看高清 | 久久久影院官网 | 久久夜色精品国产亚洲aⅴ 91chinesexxx | 超碰国产97 | 97人人模人人爽人人喊中文字 | 日韩欧美不卡 | 三级免费黄色 | 久久成人精品视频 | 玖玖在线播放 | 中文字幕电影一区 | 91久久偷偷做嫩草影院 | 狠狠色丁香久久婷婷综合丁香 | 波多野结衣久久精品 | 日韩黄色免费在线观看 | 亚洲一区二区三区miaa149 | 四虎永久免费在线观看 | 国产九九九精品视频 | 久久人人艹 | 香蕉在线影院 | 高清不卡一区二区在线 | 精品国产三级a∨在线欧美 免费一级片在线观看 | 中文字幕在线看视频国产中文版 | zzijzzij亚洲日本少妇熟睡 | av在线电影播放 | 色婷婷狠狠操 | 欧美日韩在线播放一区 | 国色天香永久免费 | av网站大全免费 | 夜夜夜夜猛噜噜噜噜噜初音未来 | 日韩亚洲在线 | a v在线视频 | 久久国产一二区 | 中文国产字幕在线观看 | 久久久久久久久久久久av | 全黄色一级片 | 午夜精品久久久久久久久久久久 | 国产99久久久欧美黑人 | 日本爱爱免费视频 | 高清视频一区 | 一区中文字幕电影 | 精品国产视频一区 | 国产视频一区二区在线播放 | 91精品视频免费在线观看 | 九九综合九九综合 | 午夜精品一区二区三区四区 | 另类老妇性bbwbbw高清 | 国产精品videoxxxx | 男女免费av| 免费网站污 | 国产成人一级电影 | 天天操天天添天天吹 | 国产一级黄 | 日韩欧美国产精品 | 伊人天天综合 | 久草视频99| 国产美女视频一区 | 亚洲成人网av | av日韩国产 | 黄色99视频| 91热爆在线观看 | 最新亚洲视频 | www.夜夜草 | 亚洲国产大片 | 久久久久这里只有精品 | 日韩系列在线观看 | 色综合天天综合在线视频 | 天天干人人插 | 91精品视频在线免费观看 | 人人射网站| 伊人丁香 | 欧美日韩一级久久久久久免费看 | 日韩成年视频 | 久久免费视频6 | 这里只有精彩视频 | 91大神电影 | 国产免费又爽又刺激在线观看 | 久久免费视频网站 | 18国产精品白浆在线观看免费 | 97视频在线观看免费 | 日韩欧美一级二级 | 中文字幕在线视频精品 | 美女视频久久 | 国产麻豆传媒 | 亚洲综合精品在线 | 国产精品高清一区二区三区 | 日韩精品一区二区三区在线视频 | 亚洲黄色区 | 99精品视频在线播放免费 | 国产精品美女999 | 黄色影院在线观看 | 久久国产网站 | 91精品在线播放 | 国产精品一区二区三区免费看 | 人人澡澡人人 | 婷婷综合网 | 久久成人免费视频 | 二区三区精品 | 91九色丨porny丨丰满6 | 天天草天天草 | 97综合网| 亚洲综合最新在线 | 国内精自线一二区永久 | www久久久 | 成人av在线直播 | 操久久免费视频 | 国产精品观看视频 | 丁香五婷 | 青青河边草观看完整版高清 | 国产二区免费视频 | 狠狠色狠狠色 | 91精品在线观看入口 | 欧美激情va永久在线播放 | 人人爽人人爽人人爽人人爽 | 国产精品久久久久久久久毛片 | 久久综合福利 | 91视视频在线直接观看在线看网页在线看 | 99成人免费视频 | 中文字幕免费国产精品 | 国产中年夫妇高潮精品视频 | 久草在线视频资源 | 97视频免费在线观看 | 91精品综合在线观看 | 天天干天天弄 | 最新午夜电影 | 欧美在线视频一区二区三区 | 欧美日韩中文另类 | 久久精品人人做人人综合老师 | 91免费网 | 美女网色 | 91少妇精拍在线播放 | 国产精品久久久久久久久久久久午夜 | 911久久香蕉国产线看观看 | 国产精品免费久久久久久久久久中文 | 午夜精品久久久久久久久久久久 | 亚洲在线免费视频 | 麻豆传媒视频在线免费观看 | 麻豆视频观看 | 国产精品成人国产乱 | 中文字幕高清有码 | 黄色成人在线网站 | 国产在线超碰 | 伊人久久av | 免费视频91蜜桃 | 久久精品视频3 | 天天干天天做 | 亚洲精品高清视频在线观看 | 狠狠色丁香婷婷综合基地 | 97视频免费观看2区 亚洲视屏 | 五月天婷婷在线视频 | 亚洲精品www | 最近最新最好看中文视频 | 999日韩 | 91视频 - 114av | 狠狠干婷婷色 | 最新日韩在线 | 激情五月播播久久久精品 | 中文字幕在线观看免费高清完整版 | 国产首页 | 久久国产精品视频免费看 | 日韩亚洲精品电影 | 成人av资源网| 国产精品高潮呻吟久久久久 | 正在播放亚洲精品 | 久久av网址 | 成年美女黄网站色大片免费看 | 国产在线更新 | 毛片基地黄久久久久久天堂 | 亚洲人成在线观看 | 国产日产精品久久久久快鸭 | 嫩草伊人久久精品少妇av | 精品久久久久久久久久 | 国产麻豆视频 | 日韩中文字幕亚洲一区二区va在线 | 四虎永久精品在线 | 亚洲国产网站 | 日韩av在线一区二区 | 成人免费在线看片 | 亚洲视频在线免费观看 | 午夜久久成人 | 4hu视频| 亚洲小视频在线 | 亚洲日韩精品欧美一区二区 | 九九九九精品九九九九 | 亚洲精品自在在线观看 | 国产综合在线观看视频 | 亚洲va综合va国产va中文 | 国产精品黄色av | 精品视频资源站 | 伊人中文在线 | 99精品在这里 | 麻豆视频免费在线 | 国产成人三级在线播放 | 日日爽视频 | 国产精品原创 | 欧美日韩在线播放 | 欧美精品你懂的 | 天天干天天插伊人网 | 国产精品自拍在线 | 六月丁香久久 | 天天爱av导航 | 亚洲日本一区二区在线 | 亚洲精品色婷婷 | 久久av电影 | 在线免费91| 久久久久| 亚洲国产大片 | 日韩欧美亚州 | 欧美一二三区在线观看 | 超碰在线94 | av免费播放 | 久久午夜免费视频 | 免费视频 三区 | 91视频这里只有精品 | 999成人| 正在播放五月婷婷狠狠干 | 人人射人人澡 | 亚洲成人在线免费 | 国产美女永久免费 | 三上悠亚一区二区在线观看 | 日韩精品一卡 | 夜夜操狠狠操 | 黄色免费在线视频 | 国产精品美女久久久网av | 天天摸天天操天天舔 | 日日夜夜人人天天 | 欧美成年性 | 天天综合网入口 | av黄色国产 | 高清av影院 | 六月色婷 | 国产精品婷婷午夜在线观看 | 色99久久 | 久久精彩 | 国产99中文字幕 | 伊人看片 | 天堂av网址| 色噜噜日韩精品欧美一区二区 | 国产91精品久久久久久 | 99麻豆视频| 免费看在线看www777 | 看国产黄色片 | 亚洲九九影院 | 亚洲首页 | 婷婷伊人网 | 五月婷在线视频 | 国偷自产中文字幕亚洲手机在线 | 天天操天天爽天天干 | 国产精品视频999 | 精品影院一区二区久久久 | 激情av在线播放 | 91精品夜夜 | 久久免费福利视频 | 超碰在线中文字幕 | 色妞久久福利网 | 色综合久久久久久中文网 | 国产一区成人在线 | 在线观看网站黄 | 美女视频黄是免费的 | 99热在线观看 | 99热超碰在线 | 久久黄色免费 | 天天色宗合 | 亚洲污视频 | 国产一区在线观看视频 | 欧美日韩一级久久久久久免费看 |