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

歡迎訪問 生活随笔!

生活随笔

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

asp.net

掌握 ASP.NET 之路:自定义实体类简介 来源 :msdn

發布時間:2023/12/13 asp.net 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 掌握 ASP.NET 之路:自定义实体类简介 来源 :msdn 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

ADODB.RecordSet 和常常被遺忘的 MoveNext 的時代已經過去,取而代之的是 Microsoft ADO.NET 強大而又靈活的功能。我們的新武器就是 System.Data 名稱空間,它的特點是具有速度極快的 DataReader 和功能豐富的 DataSet,而且打包在一個面向對象的強大模型中。能夠使用這樣的工具一點都不奇怪。任何 3 層體系結構都依靠可靠的數據訪問層 (DAL) 將數據層與業務層完美地連接起來。高質量的 DAL 有助于改善代碼的重新使用,它是獲得高性能的關鍵,而且是完全透明的。

隨著工具的改進,我們的開發模式也發生了變化。告別 MoveNext 并不只是讓我們擺脫了繁瑣的語法,它還讓我們認識了斷開連接的數據,這種數據對我們開發應用程序的方式產生了深刻的影響。

因為我們已經熟悉了 DataReader(其行為與 RecordSet 非常類似),所以沒花多長時間就進一步開發出 DataAdapterDataSetDataTableDataView。正是在開發這些新對象的過程中不斷得到磨煉的技能改變了我們的開發方式。斷開連接的數據使我們可以利用新的緩存技術,從而大大提高了應用程序的性能。這些類的功能使我們能夠編寫出更智能、更強大的函數,同時還能減少(有時候甚至是大大減少)常見活動所需的代碼數量。

有些情況下非常適合使用 DataSet,例如在設計原型、開發小型系統和支持實用程序時。但是,在企業系統中使用 DataSet 可能并不是最佳的解決方案,因為對企業系統來說,易于維護要比投入市場的時間更重要。本指南的目的就是探討一種適合處理此類工作的 DataSet 的替代解決方案,即:自定義實體與集合。盡管還存在其他替代解決方案,但它們都無法提供相同的功能或無法獲得更多的支持。我們的首要任務是了解 DataSet 的缺點,以便理解我們要解決的問題。

記住,每種解決方案都有優缺點,所以 DataSet 的缺點可能比自定義實體的缺點(我們也將進行討論)更容易讓您接受。您和您的團隊必須自己決定哪個解決方案更適合您的項目。記住要考慮解決方案的總成本,包括要求改變的實質所在以及生產后所需的時間比實際開發代碼的時間更長的可能性。最后請注意,我所說的 DataSet 并不是類型化的 DataSet,但它確實可以彌補非類型化的 DataSet 的一些缺點。

返回頁首

DataSet 存在的問題

缺少抽象

尋找替代解決方案的第一個也是最明顯的原因就是 DataSet 無法從數據庫結構中提取代碼。DataAdapter 可以很好地使您的代碼獨立于基礎數據庫供應商(Microsoft、Oracle、IBM 等),但不能抽象出數據庫的核心組件:表、列和關系。這些核心數據庫組件也是 DataSet 的核心組件。DataSet 和數據庫不僅共享通用組件,不幸的是,它們還共享架構。假定有下面這樣一個 Select 語句:

SELECT UserId, FirstName, LastName FROM Users

我們知道這些值可以從 DataSet 中的 UserIdFirstNameLastName 這些 DataColumn 中獲得。

為什么會這么復雜?讓我們看一個基本的日常示例。首先我們有一個簡單的 DAL 函數:

'Visual Basic .NET Public Function GetAllUsers() As DataSet Dim connection As New SqlConnection(CONNECTION_STRING) Dim command As SqlCommand = New SqlCommand("GetUsers", connection) command.CommandType = CommandType.StoredProcedure Dim da As SqlDataAdapter = New SqlDataAdapter(command) Try Dim ds As DataSet = New DataSet da.Fill(ds) Return ds Finally connection.Dispose() command.Dispose() da.Dispose() End Try End Function //C# public DataSet GetAllUsers() { SqlConnection connection = new SqlConnection(CONNECTION_STRING); SqlCommand command = new SqlCommand("GetUsers", connection); command.CommandType = CommandType.StoredProcedure; SqlDataAdapter da = new SqlDataAdapter(command); try { DataSet ds = new DataSet(); da.Fill(ds); return ds; }finally { connection.Dispose(); command.Dispose(); da.Dispose(); } }

然后我們有一個頁面,它使用重復器顯示所有用戶:

<HTML> <body> <form id="Form1" method="post" runat="server"> <asp:Repeater ID="users" Runat="server"> <ItemTemplate> <%# DataBinder.Eval(Container.DataItem, "FirstName") %> <br /> </ItemTemplate> </asp:Repeater> </form> </body> </HTML> <script runat="server"> public sub page_load users.DataSource = GetAllUsers() users.DataBind() end sub </script>

正如我們所看到的那樣,我們的 ASPX 頁面利用 DAL 函數 GetAllUsers 作為重復器的 DataSource。如果由于某種原因(為了性能而降級、為清楚起見而進行了標準化、要求發生了變化)導致數據庫架構發生變化,變化就會一直影響 ASPX,即影響使用“FirstName”列名的 Databinder.Eval 行。這將立刻在您腦海中產生一個危險信號:數據庫架構的變化會一直影響到 ASPX 代碼嗎?聽起來不太像 N 層,對嗎?

如果我們所要做的只是對列進行簡單的重命名,那么更改本例中的代碼并不復雜。但是,如果在許多地方都使用了 GetAllUsers,更糟糕的是,如果將其作為為無數用戶提供服務的 Web 服務,那又會怎么樣呢?怎樣才能輕松或安全地傳播更改?對于這個基本示例而言,存儲過程本身作為抽象層可能已經足夠;但是依賴存儲過程獲得除最基本的保護以外的功能則可能會在以后造成更大的問題。可以將此視為一種硬編碼;實質上,使用 DataSet 時,您可能需要在數據庫架構(不管使用列名稱還是序號位置)和應用層/業務層之間建立一個嚴格的連接。但愿以前的經驗(或邏輯)已經讓您了解到硬編碼對維護工作以及將來的開發產生的影響。

DataSet 無法提供適當抽象的另一個原因是它要求開發人員必須了解基礎架構。我們所說的不是基礎知識,而是關于列名稱、類型和關系的所有知識。去掉這個要求不僅使您的代碼不像我們看到的那樣容易中斷,還使代碼更易于編寫和維護。簡單地說:

Convert.ToInt32(ds.Tables[0].Rows[i]["userId"]);

不僅難于閱讀,而且需要非常熟悉列名稱及其類型。理想情況下,您的業務層不需要知道有關基礎數據庫、數據庫架構或 SQL 的任何內容。如果您像上述代碼字符串中那樣使用 DataSet(使用 CodeBehind 并不會有任何改善),您的業務層可能會很薄。

弱類型

DataSet 屬于弱類型,因此容易出錯,還可能會影響您的開發工作。這意味著無論何時從 DataSet 中檢索值,值都以 System.Object 的形式返回,您需要對這種值進行轉換。您面臨轉換可能會失敗的風險。不幸的是,失敗不是在編譯時發生,而是在運行時發生。另外,在處理弱類型的對象時,Microsoft Visual Studio.NET (VS.NET) 等工具對您的開發人員并沒有太大的幫助。前面我們說過需要深入了解構架的知識,就是指這個意思。我們再來看一個非常常見的示例:

'Visual Basic.NET Dim userId As Integer = ? Convert.ToInt32(ds.Tables(0).Rows(0)("UserId")) Dim userId As Integer = CInt(ds.Tables(0).Rows(0)("UserId")) Dim userId As Integer = CInt(ds.Tables(0).Rows(0)(0)) //C# int userId = Convert.ToInt32(ds.Tables[0].Rows[0]("UserId"));

這段代碼顯示了從 DataSet 中檢索值的可能方法——可能您的代碼中到處都需要檢索值(如果不進行轉換,而您使用的又是 Visual Basic .NET,您可能會使用 Option Strict Off 這樣的代碼,而這會給您帶來更大的麻煩。)

不幸的是,這些代碼中的每一行都可能會產生大量的運行時錯誤:

  • 轉換可能由于以下原因而失敗:

    • 值可能為空。

    • 開發人員可能對基礎數據類型判斷有誤(還是這個問題,即開發人員需要非常熟悉數據庫架構)。

    • 如果您使用序號值,誰知道位置 X 處實際上是一個什么樣的列。

  • ds.Tables(0) 可能返回一個空引用(如果 DAL 方法或存儲過程中有任何部分失敗)。

  • “UserId”可能由于以下原因而是一個無效的列名稱:

    • 可能已經更改了名稱。

    • 可能不是由存儲過程返回的。

    • 可能包含錯別字。

  • 我們可以修改代碼并以更安全的方式編寫,即為 null/nothing 添加檢查,為轉換添加 try/catch,但這些對開發人員都沒有幫助。

    更糟糕的是,正如我們前面所說,這不是抽象的。這意味著,每次要從 DataSet 中檢索 userId 時,您都將面臨上面提到的風險,或者需要對相同的保護性步驟進行重新編程(當然,實用程序功能可能會有助于降低風險)。弱類型對象將錯誤從設計時或編譯時(這時總能夠自動檢測并輕松修復錯誤)轉移到運行時(這時的錯誤可能會出現在生產過程中,而且更難查明)。

    非面向對象

    您不能僅僅因為 DataSet 是對象,而 C# 和 Visual Basic .NET 是面向對象 (OO) 的語言就能以面向對象的方式使用 DataSet。OO 編程的“hello world”是一個典型的 Person 類,該類又是 Employee 的子類。但 DataSet 并沒有使此類繼承或其他大多數 OO 技術成為可能(或者至少使它們變得自然/直觀)。Scott Hanselman 是類實體的堅決支持者,他做出了最好的解釋:

    “DataSet 是一個對象,對嗎?但它并不是域對象,它不是一個‘蘋果’或‘桔子’,而是一個‘DataSet’類型的對象。DataSet 是一只碗(它知道支持數據存儲)。DataSet 是一個知道如何保存行和列的對象,它非常了解數據庫。但是,我不希望返回碗,我希望返回域對象,例如‘蘋果’。”1

    DataSet 使數據之間保持一種關系,使它們更強大并且能夠在關系數據庫中方便地使用。不幸的是,這意味著您將失去 OO 的所有優點。

    因為 DataSet 不能作為域對象,所以無法向它們添加功能。通常情況下,對象具有字段、屬性和方法,它們的行為針對的是類的實例。例如,您可能會將 PromoteCalcuateOvertimePay 函數與 User 對象相關聯,該對象可以通過 someUser.Promote()someUser.CalculateOverTimePay() 安全地調用。因為無法向 DataSet 添加方法,所以您需要使用實用程序功能來處理弱類型對象,并且在整個代碼中包含硬編碼值的更多實例。您一般會以過程代碼結束,在過程代碼中,您要么不斷地從 DataSet 中獲取數據,要么以繁瑣的方式將它們存儲在本地變量中并向其他位置傳遞。兩種方法都有缺點,而且都沒有任何優點。

    DataSet 相反的情況

    如果您認為數據訪問層應返回 DataSet,您可能會漏掉一些重要的優點。其中一個原因是您可能正在使用一個較薄或不存在的業務層,除了其他問題外,它還限制了您進行抽象的能力。另外,因為您使用的是一般的預編譯解決方案,所以很難利用 OO 技術。最后,Visual Studio.NET 等工具使開發人員無法輕松地利用弱類型對象(例如 DataSet),因此降低了效率并且增加了出錯的可能性。

    所有這些因素都以不同的方式對代碼的可維護性產生了直接的影響。缺乏抽象使功能改善和錯誤修復變得更復雜、更危險。您無法充分利用 OO 提供的代碼重新使用或可讀性方面的改進。當然還有一點,無論您的開發人員處理的是業務邏輯還是表示邏輯,他們都必須非常了解您的基礎數據結構。

    返回頁首

    自定義實體類

    DataSet 有關的大多數問題都可以利用 OO 編程的豐富功能在定義明確的業務層中解決。實際上,我們希望獲得按照關系組織的數據(數據庫),并將數據作為對象(代碼)使用。這個概念就是,不是獲得保存汽車信息的 DataTable,而是獲得汽車對象(稱為自定義實體或域對象)。

    在了解自定義實體之前,讓我們首先看一看我們將要面臨的挑戰。最明顯的挑戰就是所需代碼的數量。我們不是簡單地獲取數據并自動填充 DataSet,而是獲取數據并手動將數據映射到自定義實體(必須先創建好)。由于這是一項重復性的任務,我們可以使用代碼生成工具或 O/R 映射器(后文有詳細的介紹)來減輕工作量。更大的問題是將數據從關系世界映射到對象世界的具體過程。對于簡單的系統,映射通常是直接的,但是隨著復雜性的增加,這兩個世界之間的差異就會產生問題。例如,繼承在對象世界中是獲得代碼重新使用以及可維護性的重要技術。不幸的是,繼承對關系數據庫來說卻是一個陌生的概念。另外一個例子就是處理關系的方式不同:對象世界依靠維護單個對象的引用,而關系世界則是利用外鍵。

    因為代碼的數量以及關系數據和對象之間的差異不斷增加,看起來這個方法并不太適合更復雜的系統,但事實正好相反。通過將各種問題隔離到一個層中,即映射過程(同樣可以自動化),復雜的系統也可以從此方法獲益。另外,此方法已經很常用,這意味著可以通過幾種已有的設計模式徹底解決增加的復雜性。前面討論的 DataSet 的缺點在復雜系統中將成倍擴大,最后您會得出這樣一個系統,它欠缺靈活應變能力的缺點恰好超出其構建的難度。

    什么是自定義實體?

    自定義實體是代表業務域的對象,因此,它們是業務層的基礎。如果您有一個用戶身份驗證組件(本指南通篇都使用該示例進行講解),您就可能具有 UserRole 對象。電子商務系統可能具有 SupplierMerchandise 對象,而房地產公司則可能具有 HouseRoomAddress 對象。在您的代碼中,自定義實體只是一些類(實體和“類”之間具有非常密切的關系,就像在 OO 編程中使用的那樣)。一個典型的 User 類可能如下所示:

    'Visual Basic .NET Public Class User #Region "Fields and Properties" Private _userId As Integer Private _userName As String Private _password As String Public Property UserId() As Integer Get Return _userId End Get Set(ByVal Value As Integer) _userId = Value End Set End Property Public Property UserName() As String Get Return _userName End Get Set(ByVal Value As String) _userName = Value End Set End Property Public Property Password() As String Get Return _password End Get Set(ByVal Value As String) _password = Value End Set End Property #End Region #Region "Constructors" Public Sub New() End Sub Public Sub New(id As Integer, name As String, password As String) Me.UserId = id Me.UserName = name Me.Password = password End Sub #End Region End Class //C# public class User { #region "Fields and Properties" private int userId; private string userName; private string password; public int UserId { get { return userId; } set { userId = value; } } public string UserName { get { return userName; } set { userName = value; } } public string Password { get { return password; } set { password = value; } } #endregion #region "Constructors" public User() {} public User(int id, string name, string password) { this.UserId = id; this.UserName = name; this.Password = password; } #endregion }

    為什么能夠從它們獲益?

    使用自定義實體獲得的主要好處來自這樣一個簡單的事實,即它們是完全受您控制的對象。具體而言,它們允許您:

    • 利用繼承和封裝等 OO 技術。

    • 添加自定義行為。

    例如,我們的 User 類可以通過為其添加 UpdatePassword 函數而受益(我們可能會使用外部/實用程序函數對數據集執行此類操作,但會影響可讀性/維護性)。另外,它們屬于強類型,這表示我們可以獲得 IntelliSense 支持:

    1 User 類的 IntelliSense

    最后,因為自定義實體為強類型,所以不太需要進行容易出錯的強制轉換:

    Dim userId As Integer = user.UserId '與 Dim userId As Integer = ? Convert.ToInt32(ds.Tables("users").Rows(0)("UserId")) 返回頁首

    對象關系映射

    正如前文所討論的那樣,此方法的主要挑戰之一就是處理關系數據和對象之間的差異。因為我們的數據始終存儲在關系數據庫中,所以我們只能在這兩個世界之間架起一座橋梁。對于上文的 User 示例,我們可能希望在數據庫中建立一個如下所示的用戶表:

    2 User 的數據視圖

    從這個關系架構映射到自定義實體是一個非常簡單的事情:

    'Visual Basic .NET Public Function GetUser(ByVal userId As Integer) As User Dim connection As New SqlConnection(CONNECTION_STRING) Dim command As New SqlCommand("GetUserById", connection) command.Parameters.Add("@UserId", SqlDbType.Int).Value = userId Dim dr As SqlDataReader = Nothing Try connection.Open() dr = command.ExecuteReader(CommandBehavior.SingleRow) If dr.Read Then Dim user As New User user.UserId = Convert.ToInt32(dr("UserId")) user.UserName = Convert.ToString(dr("UserName")) user.Password = Convert.ToString(dr("Password")) Return user End If Return Nothing Finally If Not dr is Nothing AndAlso Not dr.IsClosed Then dr.Close() End If connection.Dispose() command.Dispose() End Try End Function //C# public User GetUser(int userId) { SqlConnection connection = new SqlConnection(CONNECTION_STRING); SqlCommand command = new SqlCommand("GetUserById", connection); command.Parameters.Add("@UserId", SqlDbType.Int).Value = userId; SqlDataReader dr = null; try{ connection.Open(); dr = command.ExecuteReader(CommandBehavior.SingleRow); if (dr.Read()){ User user = new User(); user.UserId = Convert.ToInt32(dr["UserId"]); user.UserName = Convert.ToString(dr["UserName"]); user.Password = Convert.ToString(dr["Password"]); return user; } return null; }finally{ if (dr != null && !dr.IsClosed){ dr.Close(); } connection.Dispose(); command.Dispose(); } }

    我們仍然按照通常的方式設置連接和命令對象,但接著創建了 User 類的一個新實例并從 DataReader 中填充該實例。您仍然可以在此函數中使用 DataSet 并將其映射到您的自定義實體,但 DataSet 相對于 DataReader 的主要好處是前者提供了數據的斷開連接的視圖。在本例中,User 實例提供了斷開連接的視圖,使我們可以利用 DataReader 的速度。

    等一下!您并沒有解決任何問題!

    細心的讀者可能注意到我前面提到 DataSet 的問題之一是它們并非強類型,這導致效率降低并增加了出現運行時錯誤的可能性。它們還需要開發人員深入了解基礎數據結構。看一看上文的代碼,您可能會注意到這些問題依然存在。但請注意,我們已經將這些問題封裝到一個非常孤立的代碼區域內;這表示您的類實體的使用者(Web 界面、Web 服務使用者、Windows 表單)仍然完全沒有意識到這些問題。相反,使用 DataSet 可以將這些問題分散到整個代碼中。

    改進

    上文的代碼對顯示映射的基本概念很有用,但可以在兩個關鍵的方面進行改進。首先,我們需要提取并將代碼填充到其自己的函數中,因為代碼有可能會被重新使用:

    'Visual Basic .NET Public Function PopulateUser(ByVal dr As IDataRecord) As User Dim user As New User user.UserId = Convert.ToInt32(dr("UserId")) '檢查 NULL 的示例 If Not dr("UserName") Is DBNull.Value Then user.UserName = Convert.ToString(dr("UserName")) End If user.Password = Convert.ToString(dr("Password")) Return user End Function //C# public User PopulateUser(IDataRecord dr) { User user = new User(); user.UserId = Convert.ToInt32(dr["UserId"]); //檢查 NULL 的示例 if (dr["UserName"] != DBNull.Value){ user.UserName = Convert.ToString(dr["UserName"]); } user.Password = Convert.ToString(dr["Password"]); return user; }

    第二個需要注意的事項是,我們不對映射函數使用 SqlDataReader,而是使用 IDataRecord。這是所有 DataReader 實現的接口。使用 IDataRecord 使我們的映射過程獨立于供應商。也就是說,我們可以使用上一個函數從 Access 數據庫中映射 User,即使它使用 OleDbDataReader 也可以。如果您將這個特定的方法與 Provider Model Design Pattern(鏈接 1、鏈接 2)結合使用,您的代碼就可以輕松地用于不同的數據庫提供程序。

    最后,以上代碼說明了封裝的強大功能。處理 DataSet 中的 NULL 并非最簡單的事,因為每次提取值時都需要檢查它是否為 NULL。使用上述填充方法,我們在一個地方就輕松地解決了此問題,使我們的客戶無需處理它。

    映射到何處?

    關于此類數據訪問和映射函數的歸屬問題存在一些爭論,即究竟是作為獨立類的一部分,還是作為適當自定義實體的一部分。將所有用戶相關的任務(獲取數據、更新和映射)都作為 User 自定義實體的一部分當然很不錯。這在數據庫架構與自定義實體很相似時會很有用(比如在本例中)。隨著系統復雜性的增加,這兩個世界的差異開始顯現出來,將數據層和業務層明確分離對簡化維護有很大的幫助(我喜歡將其稱為數據訪問層)。將訪問和映射代碼放在其自己的層 (DAL) 上有一個副作用,即它為確保數據層與業務層的明確分離提供了一個嚴格的原則:

    永遠不要從 System.Data 返回類或從 DAL 返回子命名空間

    返回頁首

    自定義集合

    到目前為止,我們只了解了如何處理單個實體,但您經常需要處理多個對象。一個簡單的解決方案是將多個值存儲在一個一般的集合(例如 Arraylist)中。這并非最理想的解決方案,因為它又產生了與 DataSet 有關的一些問題,即:

    • 它們不是強類型,并且

    • 無法添加自定義行為。

    最能滿足我們需求的解決方案是創建我們自己的自定義集合。幸虧 Microsoft .NET Framework 提供了一個專門為了此目的而繼承的類:CollectionBase CollectionBase 的工作原理是,將所有類型的對象都存儲在專有 Arraylist 中,但是通過只接受特定類型(例如 User 對象)的方法來提供對這些專有集合的訪問。也就是說,將弱類型代碼封裝在強類型的 API 中。

    雖然自定義集合可能看起來有很多代碼,但大多數都可以由代碼生成功能或通過剪切和粘貼方便地完成,并且通常只需要一次搜索和替換即可。讓我們看一看構成 User 類的自定義集合的不同部分:

    'Visual Basic .NET Public Class UserCollection Inherits CollectionBase Default Public Property Item(ByVal index As Integer) As User Get Return CType(List(index), User) End Get Set List(index) = value End Set End Property Public Function Add(ByVal value As User) As Integer Return (List.Add(value)) End Function Public Function IndexOf(ByVal value As User) As Integer Return (List.IndexOf(value)) End Function Public Sub Insert(ByVal index As Integer, ByVal value As User) List.Insert(index, value) End Sub Public Sub Remove(ByVal value As User) List.Remove(value) End Sub Public Function Contains(ByVal value As User) As Boolean Return (List.Contains(value)) End Function End Class //C# public class UserCollection :CollectionBase { public User this[int index] { get {return (User)List[index];} set {List[index] = value;} } public int Add(User value) { return (List.Add(value)); } public int IndexOf(User value) { return (List.IndexOf(value)); } public void Insert(int index, User value) { List.Insert(index, value); } public void Remove(User value) { List.Remove(value); } public bool Contains(User value) { return (List.Contains(value)); } }

    通過實現 CollectionBase 可以完成更多任務,但上面的代碼代表了自定義集合所需的核心功能。觀察一下 Add 函數,可以看出我們只是簡單地將對 List.Add(它是一個 Arraylist)的調用封裝到僅允許 User 對象的函數中。

    映射自定義集合

    將我們的關系數據映射到自定義集合的過程與我們對自定義實體執行的過程非常相似。我們不再創建一個實體并將其返回,而是將該實體添加到集合中并循環到下一個:

    'Visual Basic .NET Public Function GetAllUsers() As UserCollection Dim connection As New SqlConnection(CONNECTION_STRING) Dim command As New SqlCommand("GetAllUsers", connection) Dim dr As SqlDataReader = Nothing Try connection.Open() dr = command.ExecuteReader(CommandBehavior.SingleResult) Dim users As New UserCollection While dr.Read() users.Add(PopulateUser(dr)) End While Return users Finally If Not dr Is Nothing AndAlso Not dr.IsClosed Then dr.Close() End If connection.Dispose() command.Dispose() End Try End Function //C# public UserCollection GetAllUsers() { SqlConnection connection = new SqlConnection(CONNECTION_STRING); SqlCommand command =new SqlCommand("GetAllUsers", connection); SqlDataReader dr = null; try{ connection.Open(); dr = command.ExecuteReader(CommandBehavior.SingleResult); UserCollection users = new UserCollection(); while (dr.Read()){ users.Add(PopulateUser(dr)); } return users; }finally{ if (dr != null && !dr.IsClosed){ dr.Close(); } connection.Dispose(); command.Dispose(); } }

    我們從數據庫中獲得數據、創建自定義集合,然后通過在結果中循環來創建每個 User 對象并將其添加到集合中。同樣要注意 PopulateUser 映射函數是如何重新使用的。

    添加自定義行為

    在討論自定義實體時,我們只是泛泛地提到可以將自定義行為添加到類中。您向實體中添加的功能類型很大程度上取決于您要實現的業務邏輯的類型,但您可能希望在自定義集合中實現某些常見的功能。一個示例就是返回一個基于某個鍵的實體,例如基于 userId 的用戶:

    'Visual Basic .NET Public Function FindUserById(ByVal userId As Integer) As User For Each user As User In List If user.UserId = userId Then Return user End If Next Return Nothing End Function //C# public User FindUserById(int userId) { foreach (User user in List) { if (user.UserId == userId){ return user; } } return null; }

    另一個示例可能是返回基于特定標準(例如部分用戶名)的用戶子集:

    'Visual Basic .NET Public Function FindMatchingUsers(ByVal search As String) As UserCollection If search Is Nothing Then Throw New ArgumentNullException("search cannot be null") End If Dim matchingUsers As New UserCollection For Each user As User In List Dim userName As String = user.UserName If Not userName Is Nothing And userName.StartsWith(search) Then matchingUsers.Add(user) End If Next Return matchingUsers End Function //C# public UserCollection FindMatchingUsers(string search) { if (search == null){ throw new ArgumentNullException("search cannot be null"); } UserCollection matchingUsers = new UserCollection(); foreach (User user in List) { string userName = user.UserName; if (userName != null && userName.StartsWith(search)){ matchingUsers.Add(user); } } return matchingUsers; }

    可以通過 DataTable.Select 以相同的方式使用 DataSets。需要說明的重要一點是,盡管創建自己的功能使您可以完全控制您的代碼,但 Select 方法為完成同樣的操作提供了一個非常方便且不需要編寫代碼的方法。但另一方面,Select 需要開發人員了解基礎數據庫,而且它不是強類型。

    綁定自定義集合

    我們看到的第一個示例是將 DataSet 綁定到 ASP.NET 控件。考慮到它很普通,您會高興地發現自定義集合綁定同樣很簡單(這是因為 CollectionBase 實現了用于綁定的 Ilist)。自定義集合可以作為任何控件的 DataSource,而 DataBinder.Eval 只能像您使用 DataSet 那樣使用:

    'Visual Basic .NET Dim users as UserCollection = DAL.GetallUsers() repeater.DataSource = users repeater.DataBind() //C# UserCollection users = DAL.GetAllUsers(); repeater.DataSource = users; repeater.DataBind(); <!-- HTML --> <asp:Repeater onItemDataBound="r_IDB" ID="repeater" Runat="server"> <ItemTemplate> <asp:Label ID="userName" Runat="server"> <%# DataBinder.Eval(Container.DataItem, "UserName") %><br /> </asp:Label> </ItemTemplate> </asp:Repeater>

    您可以不使用列名稱作為 DataBinder.Eval 的第二個參數,而指定您希望顯示的屬性名稱,在本例中為 UserName

    對于在許多數據綁定控件提供的 OnItemDataBoundOnItemCreated 中執行處理的人來說,您可能會將 e.Item.DataItem 強制轉換成 DataRowView。當綁定到自定義集合時,e.Item.DataItem 則被強制轉換成自定義實體,在我們的示例中為 User 類:

    'Visual Basic .NET Protected Sub r_ItemDataBound (s As Object, e As RepeaterItemEventArgs) Dim type As ListItemType = e.Item.ItemType If type = ListItemType.AlternatingItem OrElse ? type = ListItemType.Item Then Dim u As Label = CType(e.Item.FindControl("userName"), Label) Dim currentUser As User = CType(e.Item.DataItem, User) If Not PasswordUtility.PasswordIsSecure(currentUser.Password) Then ul.ForeColor = Drawing.Color.Red End If End If End Sub //C# protected void r_ItemDataBound(object sender, RepeaterItemEventArgs e) { ListItemType type = e.Item.ItemType; if (type == ListItemType.AlternatingItem || ? type == ListItemType.Item){ Label ul = (Label)e.Item.FindControl("userName"); User currentUser = (User)e.Item.DataItem; if (!PasswordUtility.PasswordIsSecure(currentUser.Password)){ ul.ForeColor = Color.Red; } } } 返回頁首

    管理關系

    即使在最簡單的系統中,實體之間也存在關系。對于關系數據庫,可以通過外鍵維護關系;而使用對象時,關系只是對另一個對象的引用。例如,根據我們前面的示例,User 對象完全可以具有一個 Role

    'Visual Basic .NET Public Class User Private _role As Role Public Property Role() As Role Get Return _role End Get Set(ByVal Value As Role) _role = Value End Set End Property End Class //C# public class User { private Role role; public Role Role { get {return role;} set {role = value;} } }

    或者一個 Role 集合:

    'Visual Basic .NET Public Class User Private _roles As RoleCollection Public ReadOnly Property Roles() As RoleCollection Get If _roles Is Nothing Then _roles = New RoleCollection End If Return _roles End Get End Property End Class //C# public class User { private RoleCollection roles; public RoleCollection Roles { get { if (roles == null){ roles = new RoleCollection(); } return roles; } } }

    在這兩個示例中,我們有一個虛構的 Role 類或 RoleCollection 類,它們就是類似于 UserUserCollection 類的其他自定義實體或集合類。

    映射關系

    真正的問題在于如何映射關系。讓我們看一個簡單的示例,我們希望根據 userId 及其角色來檢索一個用戶。首先,我們看一看關系模型:

    3 User Role 之間的關系

    這里,我們看到了一個 User 表和一個 Role 表,我們可以將這兩個表都以直觀的方式映射到自定義實體。我們還有一個 UserRoleJoin 表,它代表了 UserRole 之間的多對多關系。

    然后,我們使用存儲過程來獲取兩個單獨的結果:第一個代表 User,第二個代表該用戶的 Role

    CREATE PROCEDURE GetUserById( @UserId INT )AS SELECT UserId, UserName, [Password] FROM Users WHERE UserId = @UserID SELECT R.RoleId, R.[Name], R.Code FROM Roles R INNER JOIN UserRoleJoin URJ ON R.RoleId = URJ.RoleId WHERE URJ.UserId = @UserId

    最后,我們從關系模型映射到對象模型:

    'Visual Basic .NET Public Function GetUserById(ByVal userId As Integer) As User Dim connection As New SqlConnection(CONNECTION_STRING) Dim command As New SqlCommand("GetUserById", connection) command.Parameters.Add("@UserId", SqlDbType.Int).Value = userId Dim dr As SqlDataReader = Nothing Try connection.Open() dr = command.ExecuteReader() Dim user As User = Nothing If dr.Read() Then user = PopulateUser(dr) dr.NextResult() While dr.Read() user.Roles.Add(PopulateRole(dr)) End While End If Return user Finally If Not dr Is Nothing AndAlso Not dr.IsClosed Then dr.Close() End If connection.Dispose() command.Dispose() End Try End Function //C# public User GetUserById(int userId) { SqlConnection connection = new SqlConnection(CONNECTION_STRING); SqlCommand command = new SqlCommand("GetUserById", connection); command.Parameters.Add("@UserId", SqlDbType.Int).Value = userId; SqlDataReader dr = null; try{ connection.Open(); dr = command.ExecuteReader(); User user = null; if (dr.Read()){ user = PopulateUser(dr); dr.NextResult(); while(dr.Read()){ user.Roles.Add(PopulateRole(dr)); } } return user; }finally{ if (dr != null && !dr.IsClosed){ dr.Close(); } connection.Dispose(); command.Dispose(); } }

    User 實例即被創建和填充;我們轉移到下一個結果/選擇并進行循環,填充 Role 并將它們添加到 User 類的 RolesCollection 屬性中。

    返回頁首

    高級內容

    本指南的目的是介紹自定義實體與集合的概念及使用。使用自定義實體是業界廣泛采用的做法,因此,也就產生了同樣多的模式以處理各種情況。設計模式具有優勢的原因有很多。首先,在處理具體的情況時,您可能不是第一次碰到某個給定的問題。設計模式使您可以重新使用給定問題的已經過嘗試和測試的解決方案(雖然設計模式并不意味著全盤照抄,但它們幾乎總是能夠為解決方案提供一個可靠的基礎)。相應地,這使您對系統隨著復雜性增加而進行縮放的能力充滿了信心,不僅因為它是一個廣泛使用的方法,還因為它具有詳盡的記錄。設計模式還為您提供了一個通用的詞匯表,使知識的傳播和傳授更容易實現。

    不能說設計模式只適用于自定義實體,實際上許多設計模式都并非如此。但是,如果您找機會試一下,您可能會驚喜地發現許多記載詳盡的模式確實適用于自定義實體和映射過程。

    最后這一部分專門介紹大型或較復雜的系統可能會碰到的一些高級情況。因為大多數主題都可能值得您單獨學習,所以我會盡量為您提供一些入門資料。

    Martin Fowler 的 Patterns of Enterprise Application Architecture 就是一個很好的入門材料,它不僅可以作為常見設計模式的優秀參考(具有詳細的解釋和大量的示例代碼),而且它的前 100 頁確實可以讓您透徹地了解整個概念。另外,Fowler 還提供了一個聯機模式目錄,它對于已經熟悉概念但需要一個便利參考的人士很有用。

    并發

    前面的示例介紹的都是從數據庫中提取數據并根據這些數據創建對象。總體而言,更新、刪除和插入數據等操作是很直觀的。我們的業務層負責創建對象、將對象傳遞給數據訪問層,然后讓數據訪問層處理對象世界與關系世界之間的映射。例如:

    'Visual Basic .NET Public sub UpdateUser(ByVal user As User) Dim connection As New SqlConnection(CONNECTION_STRING) Dim command As New SqlCommand("UpdateUser", connection) ' 可以借助可重新使用的函數對此進行反向映射 command.Parameters.Add("@UserId", SqlDbType.Int) command.Parameters(0).Value = user.UserId command.Parameters.Add("@Password", SqlDbType.VarChar, 64) command.Parameters(1).Value = user.Password command.Parameters.Add("@UserName", SqlDbType.VarChar, 128) command.Parameters(2).Value = user.UserName Try connection.Open() command.ExecuteNonQuery() Finally connection.Dispose() command.Dispose() End Try End Sub //C# public void UpdateUser(User user) { SqlConnection connection = new SqlConnection(CONNECTION_STRING); SqlCommand command = new SqlCommand("UpdateUser", connection); // 可以借助可重新使用的函數對此進行反向映射 command.Parameters.Add("@UserId", SqlDbType.Int); command.Parameters[0].Value = user.UserId; command.Parameters.Add("@Password", SqlDbType.VarChar, 64); command.Parameters[1].Value = user.Password; command.Parameters.Add("@UserName", SqlDbType.VarChar, 128); command.Parameters[2].Value = user.UserName; try{ connection.Open(); command.ExecuteNonQuery(); }finally{ connection.Dispose(); command.Dispose(); } }

    但在處理并發時就不那么直觀了,也就是說,當兩個用戶試圖同時更新相同的數據時會出現什么情況呢?默認的行為(如果您沒有執行任何操作)是最后提交數據的人將覆蓋以前所有的工作。這可能不是理想的情況,因為一個用戶的工作將在未獲得任何提示的情況下被覆蓋。要完全避免所有沖突,一種方法就是使用消極的并發技術;但此方法需要具有某種鎖定機制,這可能很難通過可縮放的方式實現。替代方法就是使用積極的并發技術。讓第一個提交的用戶控制并通知后面的用戶是通常采取的更溫和、更用戶友好的方法。這可以通過某種行版本控制(例如時間戳)來實現。

    參考資料:

    • Introduction to Data Concurrency in ADO.NET

    • CSLA.NET's concurrency techniques

    • Unit of Work design pattern

    • Optimistic offline lock design pattern

    • Pessimistic offline lock design pattern

    性能

    與合理的靈活性和功能問題相對的是,我們經常擔心細小的性能差異。盡管性能的確很重要,但提供適用于一切情況而不是最簡單情況的通用原則通常很難。例如,將自定義集合與 DataSet 相比,哪個更快?使用自定義集合,您可以大量使用 DataReader,這是從數據庫中提取數據的較快方式。但答案實際上取決于您使用它們的方式以及處理的數據類型,所以一般性的說明沒有任何用。更重要的一點是要認識到,不管您能節省多少處理時間,與維護性方面的差異相比都可能微不足道。

    當然,并不是說您不可能找到一個既具有高性能又可維護的解決方案。雖然我強調說答案實際上取決于您的使用方式,但的確有一些模式可以幫助您最大程度地提高性能。但是,首先要知道的是自定義實體與集合緩存以及 DataSet,并且能夠利用相同的機制(類似于 HttpCache)。DataSet 的優勢之一是它能夠編寫 Select 語句,以便只獲取所需的信息。使用自定義實體時,您常常感到不得不填充整個實體以及子實體。例如,如果要通過 DataSet 顯示一個 Organization 列表,您可以只提取 OganizationIdNameAddress 并將其綁定到重復器。使用自定義實體時,我總覺得還需要獲取所有其他的 Organization 信息,如果該組織通過了 ISO 認證,則可能是一個位標記,即所有員工、其他聯系信息等的集合。可能其他人沒有碰到這個大難題,但幸運的是,如果我們愿意,我們可以對自定義實體進行很好的控制。最常用的方法是使用一種延遲加載模式,它只在首次需要時獲取信息(可以很好地封裝在屬性中)。這種對各個屬性的控制提供了通過其他方式無法輕易獲得的巨大靈活性(請想象一下在 DataColumn 級別執行類似操作的情況)。

    參考資料:

    • Lazy Load 設計模式

    • CSLA.NET lazy load

    排序與篩選

    雖然 DataView 對排序和篩選的內置支持需要您了解有關 SQL 和基礎數據結構的知識,但它提供的方便確實是自定義集合所不具備的。我們仍然可以排序和篩選,但首先需要編寫功能。因為技術不一定是最先進的,所以代碼的完整描述不屬于本節要討論的范圍。大多數技術都很相似,例如使用篩選器類篩選集合以及使用比較器類進行排序,我認為不存在固定的模式。但是,的確存在一些參考資料:

    • Generic sort function

    • Sorting & Filtering Custom Collections 教程

    代碼生成

    解決概念上的障礙后,自定義實體與集合的主要缺點就是靈活性、抽象和維護性差所導致的代碼數量的增加。實際上,您可能會認為我所說的維護成本和錯誤的降低這一切都抵不上代碼的增加。雖然這一觀點是成立的(同樣,因為任何解決方案都不是完美無缺的),但可以通過設計模式和框架(例如 CSLA.NET)大大緩解此問題。代碼生成工具與模式和框架完全不同,這些工具可以大大降低您實際需要編寫的代碼數量。本指南最初打算專門辟出一節詳細介紹代碼生成工具,特別是流行的免費 CodeSmith;但現有的許多參考資料都可能超出了我自己對該產品的認識。

    在繼續之前,我認識到代碼生成聽起來像天方夜譚一樣。但經過正確的使用和理解后,它的確是您工具包中不可缺少的一個強大的武器,即使您沒有處理自定義實體也是如此。雖然代碼生成的確不僅僅適用于自定義實體,但很多都是專為自定義實體而設計的。原因很簡單:自定義實體需要大量重復代碼。

    簡言之,代碼生成是如何工作的?構想聽起來好像遙不可及甚至反而會降低效率,但您基本上通過編寫代碼(模板)來生成代碼。例如,CodeSmith 附帶了許多強大的類,使您可以連接到數據庫并獲取所有屬性:表、列(類型、大小等)和關系。獲得這些信息后,我們前面討論的大部分工作都可以自動完成。例如,開發人員可以選擇一個表,然后使用正確的模板自動創建自定義實體(帶有正確的字段、屬性和構造函數),并獲得映射函數、自定義集合以及基本的選擇、插入、更新和刪除功能。甚至還可以更進一步,實現排序、篩選以及我們提到的其他高級功能。

    CodeSmith 還附帶了許多現成的模板,可以作為很好的學習資料。最后,CodeSmith 還為實現 CSLA.NET 框架提供了許多模板。我最初只花了幾個小時來學習基本概念、熟悉 CodeSmith 的功能,但它為我節省的時間已經多得無法計算了。另外,如果所有的開發人員都使用相同的模板,代碼的高度一致性將使您能夠輕松地繼續其他人的工作。

    參考資料:

    • Code Generation with CodeSmith

    • CodeSmith 主頁

    O/R 映射器

    即使因為對 O/R 映射器知之甚少使我不敢隨便對它們發表議論,但它們自身的潛在價值使其不容忽視。代碼生成器生成基于模板的代碼,供您復制并粘貼到您自己的源代碼中,而 O/R 映射器則在運行時通過某種配置機制動態生成代碼。例如,在 XML 文件中,您可以指定某個表的列 X 映射到某個實體的屬性 Y。您仍然需要創建自定義實體,但是集合、映射和其他數據訪問函數(包括存儲過程)都是動態創建的。從理論上講,O/R 映射器幾乎可以完全解決自定義實體存在的問題。隨著關系世界和對象世界的差異越來越明顯以及映射過程越來越復雜,O/R 映射器的價值就變得越發不可限量了。O/R 映射器的兩個缺點據說就是不夠安全和性能較差(至少在 .NET 環境中是這樣)。根據我所閱讀的資料,我確信它們并不是不夠安全,雖然在有些情況下性能較差,但在另外一些情況下卻表現突出。O/R 映射器并不適合所有情況,但如果您要處理復雜的系統,則應嘗試一下它們的功能。

    參考資料:

    • Mapper 設計模式

    • Data Mapper 設計模式

    • Wilson ORMapper

    • Frans Bouma 關于 O/R 映射的帖子

    • LLBGenPro

    • NHibernate

    .NET Framework 2.0 的功能

    即將面世的 .NET Framework 2.0 版將改變我們在本指南中討論的一些實施細節。這些改變將減少支持自定義實體所需的代碼數量,并有助于處理映射問題。

    泛型

    議論頗多的泛型之所以存在,主要原因之一就是為了向開發人員提供現成的強類型的集合。我們避開 Arraylist 等現有集合是因為它們屬于弱類型。泛型提供了與當前集合同樣的方便性,而且它們屬于強類型。這是通過在聲明時指定類型來實現的。例如,我們可以替換 UserCollection 而不需要增加代碼,然后只需創建一個 List<T> 泛型的新實例并指定我們的 User 類即可:

    'Visual Basic .NET Dim users as new IList(of User) //C# IList<User> users = new IList<user>();

    聲明后,我們的 user 集合就只能處理 User 類型的對象了,這為我們提供了編譯時檢查和優化的所有優點。

    參考資料:

    • Introducing .NET Generics

    • An Introduction to C# Generics

    可以為空的類型

    可以為空的類型實際上就是由于其他原因而非上述原因而使用的泛型。處理數據庫時面臨的挑戰之一就是正確一致地處理支持 NULL 的列。在處理字符串和其他類(稱為引用類型)時,您只需為代碼中的某個變量指定 nothing/null

    'Visual Basic .NET if dr("UserName") Is DBNull.Value Then user.UserName = nothing End If //C# if (dr["UserName"] == DBNull.Value){ user.UserName = null; }

    也可以什么都不做(默認情況下,引用類型為 nothing/null)。這對值類型(例如整數布爾值小數等)并不完全一樣。您當然也可以為這些值指定 nothing/null,但這樣將會指定一個默認值。如果您只聲明整數,或者為其指定 nothing/null,變量的值實際上將為 0。這使其很難映射回數據庫:值究竟為 0 還是 null?可以為空的類型允許值類型具有具體的值或者為空,從而解決了這個問題。例如,如果我們要在 userId 列中支持 null 值(并不是很符合實際情況),我們會首先將 userId 字段和對應的屬性聲明為可以為空的類型:

    'Visual Basic .NET Private _userId As Nullable(Of Integer) Public Property UserId() As Nullable(Of Integer) Get Return _userId End Get Set(ByVal value As Nullable(Of Integer)) _userId = value End Set End Property //C# private Nullable<int> userId; public Nullable<int> UserId { get { return userId; } set { userId = value; } }

    然后利用 HasValue 屬性判斷是否指定了 nothing/null

    'Visual Basic .NET If UserId.HasValue Then Return UserId.Value Else Return DBNull.Value End If //C# if (UserId.HasValue) { return UserId.Value; } else { return DBNull.Value; }

    參考資料:

    • Nullable types in C#

    • Nullable types in VB.NET

    迭代程序

    我們前面討論的 UserCollection 示例只展示了自定義集合中可能需要的基本功能。有一個操作無法通過所提供的實現來完成,即通過一個 foreach 循環在集合中循環。要完成此操作,您的自定義集合必須具有實現 IEnumerable 接口的枚舉數支持類。這是一個非常直觀且重復性較強的過程,但卻引入了更多的代碼。C# 2.0 引入了新的 yield 關鍵字來為您處理此接口的實現細節。Visual Basic .NET 中當前沒有與新的 yield 關鍵字等效的關鍵字。

    參考資料:

    • What's new In C# 2.0 - Iterators

    • C# Iterators

    返回頁首

    小結

    請勿輕率地做出向自定義實體與集合轉換的決定。這里有許多需要考慮的因素。例如,您對 OO 概念的熟悉程度、可用來熟悉新方法的時間以及您打算部署它的環境。雖然總體上它們有很大的優點,但并不一定適合您的特定情況。即使適合您的情況,它們的缺點也可能會打消您使用它們的念頭。還要記住有許多可替代的解決方案。Jimmy Nilsson 在他的 Choosing Data Containers for .NET 中概述了其中的某些替代方案,此專欄系列包括 5 部分(1、2、3、4、5)。

    自定義實體使您獲得了面向對象的編程的豐富功能,并幫助您構建了可靠、可維護的 N 層體系結構的框架。本指南的目的之一是讓您從構成系統的業務實體,而不是一般的 DataSetDataTable 的角度來考慮您的系統。我們還討論了一些關鍵的問題,不管您選擇的途徑(即設計模式)、對象世界與關系世界的差異(了解詳細信息)以及 N 層體系結構是什么,您都應注意這些問題。請記住,您之前花費的時間會在系統的整個生命周期內為您帶來更多的回報。

    轉載于:https://www.cnblogs.com/jobin/articles/1175238.html

    總結

    以上是生活随笔為你收集整理的掌握 ASP.NET 之路:自定义实体类简介 来源 :msdn的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    又黄又爽又无遮挡免费的网站 | 色.www | 免费久久片 | 亚洲国产中文字幕在线视频综合 | 国产精品视频不卡 | 97在线观视频免费观看 | 在线免费观看一区二区三区 | 欧美日韩三级 | 国产成人精品国内自产拍免费看 | 成人av资源网 | 九热精品 | 亚洲精品中文在线观看 | 国产成人精品一区二区三区福利 | 久99热 | 欧美另类一二三四区 | 色综合天天综合网国产成人网 | av在线亚洲天堂 | 国产视频九色蝌蚪 | 免费91麻豆精品国产自产在线观看 | 日韩久久久久久久久 | 亚洲视频综合在线 | 国产99区 | 黄色片视频免费 | 久久草草热国产精品直播 | 久久精品综合网 | 日本在线中文在线 | 欧美极品少妇xxxx | 91正在播放 | 97久久精品午夜一区二区 | 日日干激情五月 | 国产福利在线免费观看 | 国产色一区 | 九月婷婷人人澡人人添人人爽 | 亚洲一区二区三区四区在线视频 | 日韩在线观看一区二区 | 国产高清在线观看 | 国产视频资源 | av高清一区 | 国产精品你懂的在线观看 | 国内成人av | 欧美人人爱 | 日韩精品在线视频免费观看 | 色婷婷免费视频 | 国产视频网站在线观看 | 天天撸夜夜操 | 一级特黄av | 麻豆视频观看 | 奇人奇案qvod | 91完整版 | 亚洲人成网站精品片在线观看 | 亚洲综合爱 | 久久免费看av | 黄色一级在线免费观看 | 日本最新一区二区三区 | 国产福利一区二区三区视频 | 中文字幕在线观看免费高清完整版 | 亚洲视频一区二区三区在线观看 | 久久久久这里只有精品 | 国产91影院 | 成人啪啪18免费游戏链接 | 丁香六月在线 | 精品国产乱码一区二 | 日韩精品在线免费观看 | 国产高清视频网 | 久久久久久久久久网 | 国产精品久久久久四虎 | 国产手机视频在线观看 | 777视频在线观看 | 在线免费试看 | 免费一区在线 | 狠狠色伊人亚洲综合网站野外 | 青春草视频在线播放 | 99久久精品国产亚洲 | 五月婷婷激情网 | 毛片a级片 | 国产精品电影在线 | 91在线你懂的| 欧美综合在线视频 | 日韩精品欧美视频 | 97在线观看视频 | 干干夜夜 | 亚洲黄色av网址 | 三级黄色免费片 | 婷婷激情综合网 | 国内视频 | 亚洲免费不卡 | 国产精品视频你懂的 | 91福利视频免费观看 | 黄色av网站在线观看免费 | 日韩免费在线播放 | 五月婷婷天堂 | 色91在线| 久草剧场 | 久久伊人精品一区二区三区 | 日韩系列在线观看 | 精品夜夜嗨av一区二区三区 | 一级免费黄色 | 91精品系列| 色99网 | 亚洲成人免费观看 | 中文字幕在线观看三区 | 日本护士三级少妇三级999 | 免费男女网站 | 国产中的精品av小宝探花 | 天天干天天操天天干 | 99热网站| 国产 亚洲 欧美 在线 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 91av原创 | 国产精品12 | 五月天欧美精品 | 午夜日b视频 | 91福利视频网站 | 亚洲精品国产欧美在线观看 | 欧美精品久久久久久久久久丰满 | 欧美日韩午夜爽爽 | 美女国产| 成年人三级网站 | 特黄特色特刺激视频免费播放 | 久久任你操| 免费黄色网止 | 日韩视频一 | 丁香综合激情 | 99热这里只有精品免费 | 午夜18视频在线观看 | 久久久久久国产精品免费 | 色综合亚洲精品激情狠狠 | 97成人在线 | 91av视频在线免费观看 | 免费99| 日韩精品网址 | 91成人区 | 国产美女主播精品一区二区三区 | 在线观看亚洲免费视频 | www黄色av| 911香蕉| 最近中文字幕大全中文字幕免费 | 男女全黄一级一级高潮免费看 | 久久久麻豆视频 | 五月婷综合 | 黄色在线免费观看网站 | 97精品国产97久久久久久粉红 | 国产精品美女久久久 | 人人插人人爱 | 亚洲美女精品区人人人人 | 丰满少妇高潮在线观看 | 久久精品国产一区二区三 | 久久,天天综合 | 国产九九九精品视频 | 五月婷婷六月丁香 | 国产不卡免费视频 | 国产视频精品在线 | 91人人干 | 国产精品丝袜在线 | 最近中文字幕在线中文高清版 | 夜夜操狠狠操 | 午夜精品久久久久久久久久久 | 久久亚洲精品国产亚洲老地址 | 亚洲精品乱码久久 | 亚洲午夜久久久影院 | 日韩精品综合在线 | 久久中文字幕视频 | 国产欧美在线一区二区三区 | 99产精品成人啪免费网站 | 伊人电影在线观看 | 国产成人精品一区二区三区福利 | 久久视频一区二区 | 四虎在线影视 | 中文av免费| 天天拍天天色 | 国产精品一区二区 91 | 中文字幕一区二区三区精华液 | 国产一区在线不卡 | 婷婷国产在线 | 丁香午夜 | 国产精品中文字幕在线 | 亚洲理论在线观看 | 中文字幕乱码日本亚洲一区二区 | 少妇性色午夜淫片aaaze | 亚洲精品在 | 97国产在线 | 91成人精品观看 | 久久伦理 | 色综合天天色综合 | 中文字幕大全 | 亚洲视频中文 | 国产区高清在线 | 91视频免费看网站 | 丁香资源影视免费观看 | 久碰视频在线观看 | 天天婷婷 | 亚洲第二色 | 色综合中文综合网 | 国产一区二区网址 | 一二区电影 | 久久久91精品国产一区二区三区 | 亚洲国产偷 | 欧美大片在线观看一区 | 亚洲激情电影在线 | www.五月天色 | 欧美日韩免费视频 | 国产精品久久久久久一区二区 | 92国产精品久久久久首页 | 久久国产精品系列 | 在线观看黄色大片 | 久久综合中文字幕 | www.99av| 国产精品嫩草影视久久久 | 亚洲一区不卡视频 | 日韩天堂网 | 久久久久久久久久久免费av | 久久伊人八月婷婷综合激情 | 国产高清视频网 | 欧美激情精品久久久久久免费印度 | 综合久久综合久久 | 中文字幕亚洲不卡 | 国产v在线 | 亚洲精品在线播放视频 | 97在线观 | 欧美91视频| 久久国产免 | 久久免费黄色 | 亚洲国产影院av久久久久 | 丁香在线观看完整电影视频 | 国产在线色站 | 日韩 在线a | 91国内在线 | 天堂在线一区二区三区 | 8090yy亚洲精品久久 | 国产精品一区二区果冻传媒 | 一区二区视频免费在线观看 | 国内视频1区 | 欧美日韩免费一区二区 | 日韩免费看的电影 | 日日碰狠狠添天天爽超碰97久久 | 亚洲日本欧美在线 | 亚洲精品欧美专区 | 国产高清久久久久 | 免费看高清毛片 | 成人作爱视频 | 天天综合日日夜夜 | 97精品视频在线 | 视频在线观看入口黄最新永久免费国产 | 久久久91精品国产 | 伊人久久五月天 | 999久久精品 | 天海翼一区二区三区免费 | 99久久婷婷国产精品综合 | 欧美精品亚洲二区 | 亚州日韩中文字幕 | 免费观看久久 | 九九热中文字幕 | 日韩精品久久久久久久电影竹菊 | 婷婷久月| 97视频入口免费观看 | 福利视频网站 | 中文字幕在线观看你懂的 | 手机成人在线 | 国产69精品久久99不卡的观看体验 | av成人资源 | av大片网站 | 在线观看视频一区二区三区 | 97电影网手机版 | 91av综合| 亚洲人成影院在线 | 成在人线av | 91免费视频黄 | 欧美日韩性视频 | 国产成人亚洲在线观看 | 激情视频一区二区 | 91精品国产91久久久久久三级 | 免费a级毛片在线看 | 美国三级黄色大片 | 一级成人在线 | 97超碰资源网 | 91看片淫黄大片一级在线观看 | 国产小视频你懂的在线 | 日韩成人黄色av | 天天操操操操操 | 免费看久久| 久久字幕网| 在线观看精品黄av片免费 | 日本三级中文字幕在线观看 | 婷婷综合久久 | 久艹在线播放 | 久久成人久久 | 国产黄免费看 | 欧美精品中文字幕亚洲专区 | 精品在线视频观看 | 国产成年免费视频 | 四虎在线永久免费观看 | 18国产精品白浆在线观看免费 | 日韩欧三级 | 激情五月婷婷激情 | 九九视频热| 精品国产视频一区 | 久久综合九色综合网站 | 欧美污污网站 | 日韩丝袜视频 | 日韩色中色 | 日韩精品免费一区二区三区 | 中国一级片在线播放 | 97在线免费观看 | 精品国产一区二区在线 | 亚洲成人av一区二区 | 激情视频国产 | 九九99| 97视频在线观看视频免费视频 | av丁香| 国产91精品高清一区二区三区 | 亚洲电影黄色 | 在线观看网站你懂的 | 91视频免费播放 | 97激情影院 | 亚洲国产成人高清精品 | 五月婷婷激情综合网 | 国产伦精品一区二区三区在线 | 天天做天天爱夜夜爽 | 亚洲人成人在线 | 国产91精品一区二区麻豆亚洲 | 色婷婷综合久久久久中文字幕1 | 国产一区二区综合 | av网站免费看 | 五月婷丁香网 | 欧美一区影院 | 最新色视频 | 九九热久久久 | 日韩最新在线 | www成人av | 一区二区三区免费在线播放 | 国产精品久久久久久99 | 国产精品久久久久av免费 | 亚洲国产日韩欧美在线 | 成人动漫一区二区 | 午夜骚影 | 免费大片黄在线 | 97成人精品视频在线观看 | 91夫妻视频 | 在线观看91视频 | 国产精品剧情 | 西西人体www444| 一级成人免费 | 免费成人在线观看 | 一区二区成人国产精品 | 国产精品久久久久一区二区三区 | 久久免费精品一区二区三区 | www.久久色.com | 808电影免费观看三年 | 97电影网站| 国内视频在线观看 | 中文字幕在线不卡国产视频 | 天天爽天天碰狠狠添 | 欧美成人精品在线 | 亚洲国产精品激情在线观看 | 亚洲黄色av网址 | 91久久偷偷做嫩草影院 | 国产精品2020| 国产高清在线一区 | 成人av网站在线观看 | 婷婷精品国产一区二区三区日韩 | 在线国产91| 综合激情av | 精品高清视频 | 国产理论一区二区三区 | 9999国产精品 | 日精品 | 亚洲成人黄色网址 | 69精品| 中文字幕在线观看视频网站 | 一区二区三区在线看 | 久久久精品福利视频 | 一区二精品| 911久久香蕉国产线看观看 | 日韩免费三区 | 国产美女被啪进深处喷白浆视频 | 一区二区伦理电影 | 在线观看中文字幕亚洲 | 免费黄色av片 | 玖玖色在线观看 | 五月天丁香| 中文字幕视频观看 | 99久久久国产精品美女 | 久草视频在线看 | 久久成人午夜视频 | 精品一区二三区 | 精品国产三级 | 亚洲午夜精品久久久久久久久久久久 | 中文字幕免费观看全部电影 | 99性视频 | 国产成人91 | 波多野结衣综合网 | 免费高清在线观看电视网站 | 热久久国产精品 | 久久免费看 | 中文字幕影视 | 欧美在线视频a | 在线免费观看黄色小说 | 99精品福利视频 | 国产小视频在线看 | 四虎成人av | 久久九九免费视频 | 亚洲成人高清在线 | 国产精品久久久久久久久久不蜜月 | 国产精品美女久久久久久久久久久 | 日韩一级电影网站 | 成人一区电影 | 亚洲免费在线观看视频 | 亚洲一区视频免费观看 | 99视频黄 | 在线天堂亚洲 | 操少妇视频 | bbw av| 免费日韩一区二区 | 97超碰人人模人人人爽人人爱 | 一区二区不卡在线观看 | 日色在线视频 | 成人av教育 | 91在线欧美| 日韩久久视频 | 99视频在线精品国自产拍免费观看 | 91麻豆精品国产91久久久久 | 色香蕉在线视频 | 99 精品 在线 | 韩国一区在线 | 日本成人中文字幕在线观看 | 99热这里只有精品在线观看 | 国产手机av在线 | 免费韩国av| 黄色亚洲| 天天操天天草 | 最近字幕在线观看第一季 | 免费av试看| 亚洲最新av在线网址 | 久久99最新地址 | 欧美色综合久久 | 青草草在线| 欧美激情精品久久久久久 | 精品免费观看 | 在线观看精品一区 | 国产一区二区在线免费 | 黄色片视频在线观看 | 成人精品久久久 | 正在播放国产一区 | 国产九九热视频 | 又黄又爽的免费高潮视频 | 四虎成人精品永久免费av | 亚洲女同ⅹxx女同tv | 国产精品免费一区二区三区 | 亚洲3级| 精品久久久久国产免费第一页 | 亚洲综合色婷婷 | 国产成人av福利 | 国产精品一区二区你懂的 | 亚洲日韩中文字幕在线播放 | 99精品久久精品一区二区 | 99成人在线视频 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 久久久久麻豆 | 天天操比 | 国产99久久久精品 | 伊人五月综合 | 亚洲美女视频网 | 蜜臀av性久久久久蜜臀aⅴ涩爱 | 国产中文字幕av | 日本69hd| 一级黄毛片 | 91视频啊啊啊 | 国产精品自产拍在线观看 | 亚洲1级片| 亚洲最大av在线播放 | 久久久91精品国产一区二区精品 | 中文字幕在线观看不卡 | 久久99精品久久久久久久久久久久 | 亚洲国产精品久久久久久 | 一级成人网 | 国产午夜精品一区 | 精品夜夜嗨av一区二区三区 | 国产高清av在线播放 | 亚洲第一中文字幕 | 一二三久久久 | 国产精品久久久久免费a∨ 欧美一级性生活片 | 久久成视频 | 综合色久 | av在线播放快速免费阴 | 久久久久久久久免费视频 | 天天爱天天草 | 国产精品久久网 | 国产亚洲视频在线观看 | 麻豆一级视频 | 在线看国产一区 | 亚洲国产免费看 | 一区二区中文字幕在线 | 国产91精品高清一区二区三区 | 免费中文字幕在线观看 | 一级黄色片在线观看 | 天堂久色 | 综合久久一本 | 中文字幕一区av | 欧美精品一区二区免费 | 亚洲精品黄色 | av免费在线观看1 | 精品国产乱码久久久久久三级人 | 午夜精品一区二区三区在线播放 | 视频一区二区在线观看 | av怡红院 | 日韩手机视频 | 天天操天天操天天操天天操天天操 | 国产日韩欧美在线免费观看 | 欧美在线观看视频 | 综合天天网 | 麻豆免费视频网站 | 最近中文字幕完整视频高清1 | 国产不卡在线看 | 成人一区二区三区中文字幕 | 久久精品亚洲国产 | 日本三级在线观看中文字 | 激情动态 | 国产片免费在线观看视频 | 天天干,天天操 | 激情婷婷综合网 | 国产日韩视频在线播放 | 免费在线观看一区 | 日韩欧美精品在线视频 | 天天操夜夜爱 | 精品久久久久久久久亚洲 | 国产视频二区三区 | 狠狠综合 | 在线观看91网站 | 久久精品综合网 | 久久精品成人热国产成 | 国产91全国探花系列在线播放 | 日本爱爱免费视频 | 91av在线精品 | 国产精品福利一区 | 激情综合啪啪 | 狠狠网亚洲精品 | 91一区二区三区在线观看 | 中文字幕制服丝袜av久久 | 国产视频一区在线免费观看 | 久久精品艹 | 精品在线观看免费 | 色综合激情网 | 免费黄色网址网站 | 在线免费视频a | 日韩欧美精品在线观看 | 夜添久久精品亚洲国产精品 | 国内精品久久久久影院一蜜桃 | 亚洲欧洲一区二区在线观看 | 最新99热 | 欧美乱码精品一区 | 三级av在线免费观看 | 午夜在线免费观看视频 | av天天色 | 日韩精品一区二区电影 | 国产精品一区二区精品视频免费看 | 久久精品国产免费看久久精品 | 亚洲精品理论片 | 日b黄色片| 欧美一级免费在线 | 欧美精品一区二区三区四区在线 | 欧美日韩精品免费观看 | 国产91九色蝌蚪 | 国产原创av片| 亚洲精品美女久久17c | 亚洲精品九九 | 国产精品嫩草影院9 | 免费在线观看日韩视频 | 国产精品资源在线观看 | 91自拍91| 久久精品综合一区 | 成年人免费av | 久久99精品国产99久久 | 欧美aa在线 | 婷婷五月情 | 黄色片网站大全 | 成人亚洲精品久久久久 | 亚洲精品在线视频播放 | 亚洲国产成人av网 | 久久深夜福利免费观看 | 97国产一区二区 | 国产精品久久久久国产a级 激情综合中文娱乐网 | 成人免费中文字幕 | 日韩在线一二三区 | av中文字幕网站 | 中文字幕在线视频免费播放 | 91看毛片 | 亚洲一级性 | 就要干b| 国产中文字幕在线观看 | 天天干天天拍天天操天天拍 | 91精品毛片 | 亚洲欧美综合精品久久成人 | 九九久久国产 | 蜜臀精品久久久久久蜜臀 | 国产精品毛片久久久 | 精品99999 | 色综合天天狠天天透天天伊人 | 特级黄色片免费看 | 精品国偷自产国产一区 | 天天操天天添天天吹 | 久久久久久久久久久久国产精品 | 精品自拍网 | 日韩在线视频网址 | 国产高清一 | 超碰97中文 | 日本性生活免费看 | 亚洲欧美日韩国产一区二区 | 在线国产专区 | 天天干天天操天天拍 | 精品在线免费观看 | 精品久久久一区二区 | 中文乱码视频在线观看 | 中文字幕在线色 | 亚洲黄色在线 | 国产一区 在线播放 | 狠狠躁日日躁狂躁夜夜躁av | 精品国产成人av在线免 | 亚洲视频一区二区三区在线观看 | 国产99久久久精品视频 | 最近更新好看的中文字幕 | 欧美精品999 | 久久精品一区二区三区视频 | 五月婷婷综合网 | 亚洲精品免费在线观看 | 色婷婷狠狠干 | www.99av | 国产主播99| 这里只有精品视频在线 | 超碰免费久久 | 日本中文字幕在线一区 | 免费观看xxxx9999片 | 黄色av免费看 | wwxxx日本| 国内精品久久久久 | 最新av在线免费观看 | www.久久成人 | 国产又粗又硬又长又爽的视频 | 国产在线观看你懂得 | 欧美日韩国产精品一区二区 | 久久免费视频在线观看30 | 国产高清 不卡 | 激情视频91 | 亚洲在线a | 日韩精品中文字幕在线不卡尤物 | 超碰97在线人人 | av丁香| 九九热精品视频在线播放 | 日韩成人精品在线观看 | 婷婷六月丁 | 国产一级黄色片免费看 | 91av在线视频免费观看 | 精品三级av | 亚洲国产一区在线观看 | 在线中文字幕播放 | 亚洲国产日韩欧美在线 | 国产成人精品亚洲日本在线观看 | 国产精品精品久久久久久 | 丁香婷婷激情国产高清秒播 | 精品少妇一区二区三区在线 | 五月婷婷欧美视频 | 精品国精品自拍自在线 | 免费观看一级视频 | 九九av| 亚洲精品一区二区三区在线观看 | 99视频这里有精品 | 国产一区二区三区四区大秀 | 国产精品黄色影片导航在线观看 | 丁香5月婷婷久久 | 婷婷丁香六月天 | 免费av一级电影 | 99久久国产免费看 | 国产激情电影综合在线看 | 国产黄色资源 | 久久久黄色 | 五月激情电影 | 久久久久久久久影视 | 国产亚洲精品免费 | 久久视频在线观看免费 | 蜜桃视频在线观看一区 | 一区二区视频电影在线观看 | 日韩精品久久久久 | 日韩av中文| 99精品国产免费久久 | 黄p网站在线观看 | 午夜性盈盈| 国产精品不卡一区 | 欧美日韩不卡一区二区 | 综合网中文字幕 | 欧美日韩国产一区二区三区在线观看 | 国产在线91在线电影 | 成人黄视频 | 成人黄色大片网站 | 激情视频久久 | 亚洲黄色软件 | 激情久久一区二区三区 | 91九色视频 | 日韩黄色一级电影 | 午夜视频在线观看一区二区三区 | 久久精品国产亚洲aⅴ | 亚洲狠狠丁香婷婷综合久久久 | a黄色一级 | 国产中文字幕在线观看 | 大荫蒂欧美视频另类xxxx | 最近中文字幕在线中文高清版 | av在线官网 | 日日日干| 深夜免费网站 | 久草资源免费 | 精品久久久久久久久久久久久久久久久久 | 精品亚洲成a人在线观看 | 丁香婷婷成人 | 青青视频一区 | 手机在线视频福利 | 国产亚洲欧美一区 | 成人免费看电影 | 欧美精品二区 | 国产精品美女网站 | 国产精品 日韩 欧美 | 91精品系列 | 久久久免费电影 | 久久婷婷一区 | 婷婷色中文网 | av中文字幕在线观看网站 | 五月天婷婷在线视频 | 婷婷视频在线播放 | 久草在线资源网 | 2019久久精品 | 亚洲天堂视频在线 | 久久一久久| 欧美不卡视频在线 | 国产午夜av | av在线成人| 九色91在线视频 | 国产免费激情久久 | 天堂视频一区 | 99久久精品电影 | 欧美日韩国产免费视频 | www.久久久精品 | 成人免费xxx在线观看 | 国产精品久久影院 | 中字幕视频在线永久在线观看免费 | 国产成人精品午夜在线播放 | 久久这里| 97色在线观看免费视频 | 91尤物在线播放 | 99色在线观看视频 | 久久69精品 | 超碰在线cao | 日韩欧美视频在线观看免费 | 亚洲美女视频在线观看 | 97国产大学生情侣酒店的特点 | 日本高清xxxx | 三级黄色片子 | 日本3级在线观看 | 大型av综合网站 | 久久久精品久久日韩一区综合 | av黄色影院 | 亚洲欧美视频一区二区三区 | 国产一区二区中文字幕 | 久久av中文字幕片 | 精品久久久久久综合 | 精品久久久久久久久久久久久久久久久久 | 婷婷在线视频观看 | 亚洲aⅴ免费在线观看 | 欧美日韩网站 | 黄色免费网站下载 | 天天玩夜夜操 | 国产精品免费久久久久久 | 91精品国产92久久久久 | 99精品欧美一区二区 | 亚洲国产精品成人va在线观看 | 国产精品 视频 | 九九热精品国产 | 日韩欧美在线高清 | 在线观看免费观看在线91 | 国产精品久久久久999 | www.天天综合 | 91麻豆精品国产 | 伊人久久一区 | 亚洲欧美精品一区 | 狠狠干电影 | 视频1区2区 | 国产1区在线 | 午夜精品99久久免费 | 玖玖爱在线观看 | 国产精品免费久久久久久 | 五月激情天 | 国产高清不卡一区二区三区 | 黄网站色视频免费观看 | 亚洲一区二区三区miaa149 | 久热这里有精品 | 99精品视频在线观看视频 | 久草精品免费 | 青青河边草观看完整版高清 | www.大网伊人 | 高清视频一区 | av在线免费观看黄 | 国产亚洲人 | 91超碰免费在线 | 最近更新中文字幕 | 久久99久久99免费视频 | 欧美黑人性猛交 | 国产综合精品久久 | 久久九九久久精品 | 国产精品爽爽爽 | 亚洲精品中文在线资源 | 99久久精品免费看国产一区二区三区 | 日韩在线欧美在线 | 欧美最猛性xxxxx亚洲精品 | 日韩欧美在线视频一区二区 | 亚洲电影成人 | 麻豆国产电影 | 国产电影一区二区三区四区 | 欧美一级电影 | 偷拍福利视频一区二区三区 | 成人黄色片免费看 | 国产精品中文字幕在线 | 亚洲精品99久久久久久 | 亚洲天堂网在线视频 | 久精品视频 | 天天天在线综合网 | 国产成人精品一区二区 | av久久在线 | 黄色一区二区在线观看 | 久久1电影院 | 精品久久国产精品 | 欧美精品一区二区三区四区在线 | 久久免费的视频 | 免费在线国产视频 | 色综合久久天天 | 狠狠地日 | 亚洲人人精品 | 亚州国产精品久久久 | 久久一区二 | 久久久精品一区二区三区 | 日韩在线视频一区二区三区 | 日韩中文免费视频 | 黄色视屏av| 韩日精品中文字幕 | 国产高清在线看 | 99情趣网视频 | 久久69av| 青草视频免费观看 | 一级一片免费观看 | 91精品国自产在线 | 国产成本人视频在线观看 | 久久国产精品精品国产色婷婷 | av亚洲产国偷v产偷v自拍小说 | 五月婷在线播放 | 国产九色视频在线观看 | 国产乱码精品一区二区三区介绍 | 国产黄色一级片 | 99在线视频免费观看 | 激情综合婷婷 | 日韩av福利在线 | 国产欧美精品一区aⅴ影院 99视频国产精品免费观看 | 最新av免费在线观看 | 特级毛片在线免费观看 | 日韩中字在线 | 黄色软件在线看 | 网站在线观看你们懂的 | 丁香六月婷婷综合 | 激情开心网站 | 成年人在线观看 | 久久一及片 | 在线观看你懂的网址 | 亚洲人成影院在线 | 狠狠色噜噜狠狠狠合久 | 免费a视频在线观看 | 免费在线成人av | 久久久精品国产一区二区电影四季 | 69视频永久免费观看 | 日韩免费av片 | 天天操天天摸天天爽 | 2019中文字幕网站 | 国产成人亚洲在线观看 | 亚洲狠狠干 | 亚洲欧美视频在线 | 免费美女久久99 | 久久免费激情视频 | 亚洲国产成人高清精品 | 精品一区二区三区久久 | 欧美一级片在线免费观看 | 日韩精品极品视频 | 婷婷色视频 | 亚洲精品乱码久久久久久蜜桃动漫 | 国产在线久久久 | 一级黄色免费网站 | 国产在线a不卡 | 91在线网址 | 成年人国产视频 | 91试看| 成人久久久久久久久久 | 六月色丁 | 九九色在线观看 | 色偷偷88888欧美精品久久久 | 中文字幕在线观看视频一区二区三区 | 在线国产91 | www.xxxx变态.com | 国产精品久久久久久久久久久久午 | 亚洲成av人影院 | 99精品免费久久久久久久久 | 视频三区在线 | 日批在线看 | 久久久久北条麻妃免费看 | 国产91在线免费视频 | 天天操天天干天天操天天干 | 欧美日韩国产区 | 欧美极品久久 | 天天射天天爽 | 999久久| 麻豆视频免费观看 | 日韩在线观看精品 | 亚洲伦理一区二区 | 99精品视频在线观看视频 | 亚洲国产久 | 午夜精品久久久久久久久久 | 国产无吗一区二区三区在线欢 | 精品久久久久久久久久岛国gif | 国产成人一区二区三区久久精品 | 国产日韩亚洲 | 成人h视频 | 亚洲精品字幕在线 | 亚洲精品a区 | 在线亚洲欧美日韩 | 国产精品久久久久影院 | 国产呻吟在线 | 婷婷丁香在线视频 | 久久久国产一区 | 成人蜜桃视频 | av成人动漫在线观看 | 麻豆91在线看 | 成 人 黄 色 视频 免费观看 | 国产精品日韩欧美 | 日韩网站在线观看 | 免费91麻豆精品国产自产在线观看 | 欧美乱码精品一区 | 国产精品一区二区三区在线免费观看 | 国产午夜免费视频 | 国产精品久久亚洲 | 热久久这里只有精品 | 国产精品中文字幕在线观看 | 欧美极品xxx | 久久久久久久久艹 | 日韩在线视频二区 | 四虎www | 国产伦精品一区二区三区高清 | 色99网| 国产糖心vlog在线观看 | 国产一级视频在线观看 | 日韩在线观看中文 | 亚洲一区网 | 日本精品一区二区在线观看 | 国语自产偷拍精品视频偷 | 久久精品国产成人 | 亚州精品在线视频 | 国产一区二区在线免费观看 | 亚洲一区二区三区四区精品 | 欧美精品在线观看免费 | 亚洲资源视频 | 午夜美女福利直播 | 亚洲黄色app | 激情综合网天天干 | 日韩有码第一页 | 日韩专区视频 | 国产999精品 | 久操久| 国产精品高清在线观看 | 亚洲欧美乱综合图片区小说区 | www.黄色小说.com | 免费影视大全推荐 | 国产亚洲精品久久久久5区 成人h电影在线观看 | 夜夜夜| 18性欧美xxxⅹ性满足 | 五月婷网站 | 国内精品久久久精品电影院 | 色网站在线看 | 久久久香蕉视频 | 欧美国产精品久久久久久免费 | 亚洲免费观看在线视频 | 国产一区视频免费在线观看 | 四虎成人在线 | 欧美色就是色 | 超碰国产在线播放 | 一区二区三区在线免费 | 久草在线免费色站 | 国产小视频福利在线 | 久久中文精品视频 | 在线观看爱爱视频 | 欧美日韩一区二区免费在线观看 | 国产成人精品免高潮在线观看 | www.夜夜操.com | 欧美一级裸体视频 | 日韩免费三区 | 成人久久| 性色xxxxhd| 久久久久国产免费免费 | 亚洲激情久久 |