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

歡迎訪問 生活随笔!

生活随笔

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

asp.net

【转】 ADO.NET最佳实践

發(fā)布時間:2023/12/10 asp.net 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转】 ADO.NET最佳实践 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本文轉(zhuǎn)自:http://blog.csdn.net/spidertan/archive/2003/12/13/17110.aspx????
??? 概述:

??? 本文在微軟站點資源的基礎上加工整理而成,意在介紹在你的ADO.NET應用程序中執(zhí)行和完成性能優(yōu)化、穩(wěn)定性和功能性方面提供最佳的解決方案;同時也包含在ADO.NET中運用已有的數(shù)據(jù)對象進行開發(fā)的最佳實踐和幫助你怎樣設計ADO.NET應用程序提供建議。

??? 本文包含以下內(nèi)容:

??? 1..NET框架中的data providers;

??? 2.對照DataSet和DataReader,分別介紹他們的最佳用途;

??? 3.如何使用DataSet、Commands和Connections;

??? 4.結(jié)合XML;

??? 5.如果你是ADO程序員,也不妨看看ADO.NET與ADO的區(qū)別和聯(lián)系;

??? 6.結(jié)合一些FAQ,更深一步討論ADO.NET觀點和使用技巧。

??? 介紹:

??? A..NET框架中的data providers

??????? Data providers在應用程序和數(shù)據(jù)庫之間扮演一個橋梁的角色,它使得你可以從一個數(shù)據(jù)庫返回查詢結(jié)果、執(zhí)行命令以及對數(shù)據(jù)集的更新等。

??? B.幾種data provider的介紹

??????? 下面表格中數(shù)據(jù)表明各種data provider以及最佳適用數(shù)據(jù)庫對象

提供者

描述

SQL Server.NET Data Provider

在.NET框架中使用System.Data.SqlClient命名空間;

建議在中間層應用程序中使用SQL Server7.0或以后版本;

建議在獨立的應用程序中使用MSDE或SQL Server7.0或更高版本;

SQL Server6.5或更早版本,必須使用OLE DB.NET Data Provider中的OLE DB Provider For SQL Server。

OLE DB.NET Data Provider

在.NET框架中使用System.Data.OleDb命名空間;

建議在中間層應用程序中使用SQL Server6.5或以前版本,或者任何在.NET框架SDK中指出的支持OLE DB接口清單的OLE DB Provider,OLE DB接口清單將在后面列出;

建議在獨立的應用程序中使用Access,中間層應用程序不建議使用Access;

不再支持為ODBC的OLE DB Provider,要訪問ODBC,使用ODBC.NET Data Provider。

ODBC.NET Data Provider

在.NET框架中使用System.Data.Odbc命名空間;

提供對使用ODBC驅(qū)動連接的數(shù)據(jù)庫的訪問;

.NET Data Provider For Oracle

在.NET框架中使用System.Data.OracleClient命名空間;

提供對Oracle數(shù)據(jù)庫的訪問。

Custom.NET Data Provider

提供一套接口,讓你可以自定義一個Data Provider;

SQLXML Managed Classes

包含SQLXML Managed Classes的最新版SQLXML3.0,使得你可以訪問SQL Server2000或以后版本的XML功能性擴展,比如執(zhí)行XML模板文件、執(zhí)行XPath查詢和使用Updategrams或Diffgrams更新數(shù)據(jù)等;在SQLXML 3.0中存儲過程和XML模板將會通過SOAP作為一種WEB服務。

??????? 表格中提到的OLE DB接口清單,在這里把它列出

OLE DB 對象

接口

OLE DB Services

IdataInitilize

DataSource

IDBInitialize
IDBCreateSession
IDBProperties
IPersist
IDBInfo*

Session

ISessionProperties
IOpenRowset
IDBSchemaRowset*
ITransactionLocal*
IDBCreateCommand*

Command

IcommandText
ICommandProperties
ICommandWithParameters*
IAccessor (only required if ICommandWithParameters is supported)
ICommandPrepare*

MultipleResults

ImultipleResults

RowSet

Irowset
IAccessor
IColumnsInfo
IColumnsRowset*
IRowsetInfo (only required if DBTYPE_HCHAPTER is supported)

Row

IRow*

Error

IerrorInfo
IErrorRecords
ISQLErrorInfo*

??? C.連接SQL Server7.0或更高版本

??????? 使用SQL Server.NET Data Provider連接SQL Server7.0或更高版本是最好的方式,在于它建立與SQL Server的直接連接而中間不需要任何的技術層銜接。如下圖一展示了各種訪問SQL Server7.0或更高版本的技術比較:

圖一(連接訪問SQL Server7.0或更高版本的各種技術比較)

??????? 以下例子演示怎樣創(chuàng)建和打開一個到SQL Server7.0或更高版本數(shù)據(jù)庫的連接:

‘Visual?Basic

Dim nwindConn As SqlConnection = New SqlConnection("Data Source=localhost;Integrated Security=SSPI;" & _?????????????????????????????????????????????????? "Initial Catalog=northwind")

nwindConn.Open()

‘C#

SqlConnection nwindConn = new SqlConnection("Data Source=localhost; Integrated Security=SSPI;" +

"Initial Catalog=northwind");

nwindConn.Open();

??? D.連接ODBC數(shù)據(jù)源

??????? ODBC.NET Data Provider,使用System.Data.Odbc命名空間,擁有為SQL Server和OLE DB的.NET Data Porvider一樣的結(jié)構(gòu),使用ODBC前綴(比如OdbcConnetion)和標準的ODBC連接字符。下面例子演示怎樣創(chuàng)建和打開一個到ODBC數(shù)據(jù)源的連接:

‘Visual?Basic

Dim nwindConn As OdbcConnection = New OdbcConnection("Driver={SQL Server};Server=localhost;" & _???????????????????????????????????????????????????? "Trusted_Connection=yes;Database=northwind")

nwindConn.Open()

‘C#

OdbcConnection nwindConn = new OdbcConnection("Driver={SQL Server};Server=localhost;" +

"Trusted_Connection=yes;Database=northwind");

nwindConn.Open();

??? E.使用DataReaders、DataSets、DataAdapters和DataViews

??????? ADO.NET使用DataSet和DataReader對象讀取數(shù)據(jù)并存儲。DataSet就好比是數(shù)據(jù)庫的直系親屬,擁有數(shù)據(jù)庫的所有表、順序和數(shù)據(jù)庫的約束(比如表間關系)。DataReader則從數(shù)據(jù)庫讀取快速的、只進的的和只讀的數(shù)據(jù)流。使用DataSet,你將會經(jīng)常使用DataAdapter(或者CommandBuilder)與你的數(shù)據(jù)庫打交道,同時,你也許會使用DataView去排序和過濾數(shù)據(jù),DataSet還允許你可以創(chuàng)建一個繼承于DataSet的子對象來表現(xiàn)數(shù)據(jù)中的表、行和列。下面圖二顯示DataSet對象模型:

圖二(DataSet對象模型)

下面將要介紹在什么時候使用DataSet或DataReader最恰當,同時也將說明如何使用DataAdapter(包括CommandBuilder)和DataView最優(yōu)化對數(shù)據(jù)的訪問。

??? F.DataSet和DataReader的比較

??????? 在設計你的應用程序時決定究竟使用DataSet還是使用DataReader,主要看在你的應用程序中要實現(xiàn)的功能性級別。

??????? 使用DataSet可以在你的應用程序中做以下事情:

??????? I.在多個離散的結(jié)果表之間導航;

??????????? 一個DataSet可以包含多個結(jié)果表,這些結(jié)果表是不連續(xù)的。你可以分開處理這些表,也可以把這些表當作父子關系進行處理。

??????? II.操作多個數(shù)據(jù)源(比如從XML文件和電子數(shù)據(jù)表等不只一個數(shù)據(jù)庫得到的混合數(shù)據(jù));

??????? 下面的例子演示從SQL Server2000的Northwind數(shù)據(jù)庫讀取一個customers表的清單和從Access2000的Northwind數(shù)據(jù)庫讀取一個orders表的清單,然后使用DataRelation在兩個表之間建立一個對應關系:

‘Visual?Basic

Dim custConn As SqlConnection= New SqlConnection("Data Source=localhost;Integrated Security=SSPI;" & _

"Initial Catalog=northwind;")

Dim custDA As SqlDataAdapter = New SqlDataAdapter("SELECT * FROM Customers", custConn)

Dim orderConn As OleDbConnection = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;" & _?????????????????????????????????????????????????????? "Data Source=c:"Program Files"Microsoft Office"" & _?????????????????????????????????????????????????????? "Office"Samples"northwind.mdb;")

Dim orderDA As OleDbDataAdapter = New OleDbDataAdapter("SELECT * FROM Orders", orderConn)

custConn.Open()

orderConn.Open()

Dim custDS As DataSet = New DataSet()

custDA.Fill(custDS, "Customers")

orderDA.Fill(custDS, "Orders")

custConn.Close()

orderConn.Close()

Dim custOrderRel As DataRelation = custDS.Relations.Add("CustOrders", _???????????????????????????????????? custDS.Tables("Customers").Columns("CustomerID"), _????????????????????????????????????custDS.Tables("Orders").Columns("CustomerID"))

Dim pRow, cRow As DataRow

For Each pRow In custDS.Tables("Customers").Rows

?Console.WriteLine(pRow("CustomerID").ToString())

?For Each cRow In pRow.GetChildRows(custOrderRel)

??? Console.WriteLine(vbTab & cRow("OrderID").ToString())

?Next

Next

‘C#

SqlConnection custConn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind;");

SqlDataAdapter custDA = new SqlDataAdapter("SELECT * FROM Customers", custConn);

OleDbConnection orderConn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;" +??????????????????????????????????????????????? "Data Source=c:""Program Files""Microsoft Office""Office""Samples""northwind.mdb;");

OleDbDataAdapter orderDA = new OleDbDataAdapter("SELECT * FROM Orders", orderConn);

custConn.Open();

orderConn.Open();

DataSet custDS = new DataSet();

custDA.Fill(custDS, "Customers");

orderDA.Fill(custDS, "Orders");

custConn.Close();

orderConn.Close();

DataRelation custOrderRel = custDS.Relations.Add("CustOrders",????????????????????????????? custDS.Tables["Customers"].Columns["CustomerID"],????????????????????????????? custDS.Tables["Orders"].Columns["CustomerID"]);

foreach (DataRow pRow in custDS.Tables["Customers"].Rows)

{

?Console.WriteLine(pRow["CustomerID"]);

?? foreach (DataRow cRow in pRow.GetChildRows(custOrderRel))

??? Console.WriteLine(""t" + cRow["OrderID"]);

}

??????? III.層中交換數(shù)據(jù)或者使用一個XML WEB服務,與DataReader不一樣的是DataSet可以被傳遞給一個遠程的客戶端;

??????????? 下面的例子演示如何創(chuàng)建一個XML WEB服務,其中使用GetCustomers取數(shù)據(jù)庫中customers表數(shù)據(jù),使用UpdateCustomers更新數(shù)據(jù)庫中數(shù)據(jù):

1.???? ‘Visual?Basic

2.???? <% @ WebService Language = "VB" Class = "Sample" %>

3.???? Imports System

4.???? Imports System.Data

5.???? Imports System.Data.SqlClient

6.???? Imports System.Web.Services

7.???? <WebService(Namespace:="http://microsoft.com/webservices/")> _

8.???? Public Class Sample

9.???? ??Public nwindConn As SqlConnection = New SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind")

10.???<WebMethod( Description := "Returns Northwind Customers", EnableSession := False )> _

11.???Public Function GetCustomers() As DataSet

12.?????Dim custDA As SqlDataAdapter = New SqlDataAdapter("SELECT CustomerID, CompanyName FROM Customers", nwindConn)

13.?????Dim custDS As DataSet = New DataSet()

14.?????custDA.MissingSchemaAction = MissingSchemaAction.AddWithKey

15.?????custDA.Fill(custDS, "Customers")

16.?????GetCustomers = custDS

17.???End Function

18.???<WebMethod( Description := "Updates Northwind Customers", EnableSession := False )> _

19.???Public Function UpdateCustomers(custDS As DataSet) As DataSet

20.?????Dim custDA As SqlDataAdapter = New SqlDataAdapter()

21.?????custDA.InsertCommand = New SqlCommand("INSERT INTO Customers (CustomerID, CompanyName) " & _????????????????????????????????????????? "Values(@CustomerID, @CompanyName)", nwindConn)

22.?????custDA.InsertCommand.Parameters.Add("@CustomerID", SqlDbType.NChar, 5, "CustomerID")

23.?????custDA.InsertCommand.Parameters.Add("@CompanyName", SqlDbType.NChar, 15, "CompanyName")

24.?????custDA.UpdateCommand = New SqlCommand("UPDATE Customers Set CustomerID = @CustomerID, " & _

25.?"CompanyName = @CompanyName WHERE CustomerID = @OldCustomerID", nwindConn)

26.?????custDA.UpdateCommand.Parameters.Add("@CustomerID", SqlDbType.NChar, 5, "CustomerID")

27.?????custDA.UpdateCommand.Parameters.Add("@CompanyName", SqlDbType.NChar, 15, "CompanyName")

28.?????Dim myParm As SqlParameter = custDA.UpdateCommand.Parameters.Add("@OldCustomerID", SqlDbType.NChar, 5, "CustomerID")

29.?????myParm.SourceVersion = DataRowVersion.Original

30.?????custDA.DeleteCommand = New SqlCommand("DELETE FROM Customers WHERE CustomerID = @CustomerID", nwindConn)

31.?????myParm = custDA.DeleteCommand.Parameters.Add("@CustomerID", SqlDbType.NChar, 5, "CustomerID")

32.?????myParm.SourceVersion = DataRowVersion.Original

33.?????custDA.Update(custDS, "Customers")

34.?????UpdateCustomers = custDS

35.???End Function

36.?End Class

37.??

38.?‘C#

39.?<% @ WebService Language = "C#" Class = "Sample" %>

40.?using System;

41.?using System.Data;

42.?using System.Data.SqlClient;

43.?using System.Web.Services;

44.?[WebService(Namespace="http://microsoft.com/webservices/")]

45.?public class Sample

46.?{

47.???public SqlConnection nwindConn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind");

48.???[WebMethod( Description = "Returns Northwind Customers", EnableSession = false )]

49.???public DataSet GetCustomers()

50.???{

51.?????SqlDataAdapter custDA = new SqlDataAdapter("SELECT CustomerID, CompanyName FROM Customers", nwindConn);

52.?????DataSet custDS = new DataSet();

53.?????custDA.MissingSchemaAction = MissingSchemaAction.AddWithKey;

54.?????custDA.Fill(custDS, "Customers");

55.?????return custDS;

56.???}

57.???[WebMethod( Description = "Updates Northwind Customers", EnableSession = false )]

58.???public DataSet UpdateCustomers(DataSet custDS)

59.???{

60.?????SqlDataAdapter custDA = new SqlDataAdapter();

61.?????custDA.InsertCommand = new SqlCommand("INSERT INTO Customers (CustomerID, CompanyName) " +????????????????????????????????????????? "Values(@CustomerID, @CompanyName)", nwindConn);

62.?????custDA.InsertCommand.Parameters.Add("@CustomerID", SqlDbType.NChar, 5, "CustomerID");

63.?????custDA.InsertCommand.Parameters.Add("@CompanyName", SqlDbType.NChar, 15, "CompanyName");

64.?????custDA.UpdateCommand = new SqlCommand("UPDATE Customers Set CustomerID = @CustomerID, " + "CompanyName = @CompanyName WHERE CustomerID = @OldCustomerID", nwindConn);

65.?????custDA.UpdateCommand.Parameters.Add("@CustomerID", SqlDbType.NChar, 5, "CustomerID");

66.?????custDA.UpdateCommand.Parameters.Add("@CompanyName", SqlDbType.NChar, 15, "CompanyName");

67.?????SqlParameter myParm = custDA.UpdateCommand.Parameters.Add("@OldCustomerID", SqlDbType.NChar, 5, "CustomerID");

68.?????myParm.SourceVersion = DataRowVersion.Original;

69.?????custDA.DeleteCommand = new SqlCommand("DELETE FROM Customers WHERE CustomerID = @CustomerID", nwindConn);

70.?????myParm = custDA.DeleteCommand.Parameters.Add("@CustomerID", SqlDbType.NChar, 5, "CustomerID");

71.?????myParm.SourceVersion = DataRowVersion.Original;

72.?????custDA.Update(custDS, "Customers");

73.?????return custDS;

74.???}

}

??????? IV.數(shù)據(jù)的再使用(比如排序、搜索或過濾數(shù)據(jù));

??????? V.執(zhí)行每行的大容量數(shù)據(jù)處理,處理DataReader掛起的連接服務已不再需要、影響性能的每一行;

??????? VI.使用諸如XSLT轉(zhuǎn)換或者XPath查詢等XML操作的多重數(shù)據(jù)。

??????????? 下面的例子介紹如何使用XmlDataDocument同步DataSet數(shù)據(jù)和如何使用XSLT樣式文件在HTML文件中包含DataSet數(shù)據(jù),首先是XSLT樣式文件:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:template match="CustomerOrders">

?<HTML>

?<STYLE>

?BODY {font-family:verdana;font-size:9pt}

?TD?? {font-size:8pt}

?</STYLE>

??? <BODY>

??? <TABLE BORDER="1">

????? <xsl:apply-templates select="Customers"/>

??? </TABLE>

??? </BODY>

?</HTML>

</xsl:template>

<xsl:template match="Customers">

??? <TR><TD>

????? <xsl:value-of select="ContactName"/>, <xsl:value-of select="Phone"/><BR/>

??? </TD></TR>

????? <xsl:apply-templates select="Orders"/>

</xsl:template>

<xsl:template match="Orders">

?<TABLE BORDER="1">

??? <TR><TD valign="top"><B>Order:</B></TD><TD valign="top"><xsl:value-of select="OrderID"/></TD></TR>

??? <TR><TD valign="top"><B>Date:</B></TD><TD valign="top"><xsl:value-of select="OrderDate"/></TD></TR>

??? <TR><TD valign="top"><B>Ship To:</B></TD>

??????? <TD valign="top"><xsl:value-of select="ShipName"/><BR/>

??????? <xsl:value-of select="ShipAddress"/><BR/>

??????? <xsl:value-of select="ShipCity"/>, <xsl:value-of select="ShipRegion"/>?<xsl:value-of select="ShipPostalCode"/><BR/>

??????? <xsl:value-of select="ShipCountry"/></TD></TR>

?</TABLE>

</xsl:template>

</xsl:stylesheet>

??????????? 接著下面的代碼演示如何填充DataSet的數(shù)據(jù)和運用XSLT樣式:

‘Visual?Basic

Imports System

Imports System.Data

Imports System.Data.SqlClient

Imports System.Xml

Imports System.Xml.Xsl

Public Class Sample

?Public Shared Sub Main()

??? Dim nwindConn As SqlConnection = New SqlConnection("Data Source=localhost;Initial Catalog=northwind;Integrated Security=SSPI")

??? nwindConn.Open()

??? Dim myDataSet As DataSet = New DataSet("CustomerOrders")

??? Dim custDA As SqlDataAdapter = New SqlDataAdapter("SELECT * FROM Customers", nwindConn)

??? custDA.Fill(myDataSet, "Customers")

??? Dim ordersDA As SqlDataAdapter = New SqlDataAdapter("SELECT * FROM Orders", nwindConn)

??? ordersDA.Fill(myDataSet, "Orders")

??? nwindConn.Close()

??? myDataSet.Relations.Add("CustOrders",_??????????????????????????? myDataSet.Tables("Customers").Columns("CustomerID"),_??????????????????????????? myDataSet.Tables("Orders").Columns("CustomerID")).Nested = true

??? Dim xmlDoc As XmlDataDocument = New XmlDataDocument(myDataSet)

??? Dim xslTran As XslTransform = New XslTransform

??? xslTran.Load("transform.xsl")

??? Dim writer As XmlTextWriter = New XmlTextWriter("xslt_output.html", System.Text.Encoding.UTF8)

??? xslTran.Transform(xmlDoc, Nothing, writer)

??? writer.Close()

?End Sub

End Class

‘C#

using System;

using System.Data;

using System.Data.SqlClient;

using System.Xml;

using System.Xml.Xsl;

public class Sample

{

?public static void Main()

?{

??? SqlConnection nwindConn = new SqlConnection("Data Source=localhost;Initial Catalog=northwind;Integrated Security=SSPI;");

??? nwindConn.Open();

??? DataSet custDS = new DataSet("CustomerDataSet");

??? SqlDataAdapter custDA = new SqlDataAdapter("SELECT * FROM Customers", nwindConn);

??? custDA.Fill(custDS, "Customers");

??? SqlDataAdapter ordersDA = new SqlDataAdapter("SELECT * FROM Orders", nwindConn);

??? ordersDA.Fill(custDS, "Orders");

??? nwindConn.Close();

??? custDS.Relations.Add("CustOrders",

???????????????????????? custDS.Tables["Customers"].Columns["CustomerID"],

??????????????? ?????????custDS.Tables["Orders"].Columns["CustomerID"]).Nested = true;

??? XmlDataDocument xmlDoc = new XmlDataDocument(custDS);

??? XslTransform xslTran = new XslTransform();

??? xslTran.Load("transform.xsl");

??? XmlTextWriter writer = new XmlTextWriter("xslt_output.html", System.Text.Encoding.UTF8);

??? xslTran.Transform(xmlDoc, null, writer);

??? writer.Close();

?}

}

??????? 使用DataReader可以在你的應用程序中做以下事情:

??????? I.不需要緩存數(shù)據(jù);

??????? II.處理太大而不能存儲的數(shù)據(jù);

??????? III.需要以只進、只讀和快速方式一次性訪問數(shù)據(jù)的。

??? G.使用一個自定義的強有力的DataSet類型的好處

??????? 通過創(chuàng)建一個繼承于DataSet的子對象,你可以在運行期間執(zhí)行類型檢查和聲明。當你有了一個確定的計劃或者為你的DataSet有相關的結(jié)構(gòu),你就可以創(chuàng)建一個用行和列表述一個對象的DataSet。比如,你表露一個消費者對象的名字屬性來取代表露消費者表的一行中的名字列。有關此節(jié)詳細信息,請參考微軟站點上的文章:Working with a Typed DataSet

??? H.在自定義的DataSet中處理無效數(shù)據(jù)

??????? 通過XSD語言檢查你的DataSet確保你的DataSet適當?shù)靥幚頍o效引用。nullValue注釋使你把BBNull替換成別的字符,String.Empty;或者保留無效引用,拋出錯誤提示,提示將取決于你應用程序的上下文,默認情況是引用了無效字符。

??? I.在DataSet中刷新數(shù)據(jù)

??????? 如果你要從數(shù)據(jù)庫刷新你的DataSet,使用DataAdapter.Fill,如果你的DataTable擁有主鍵,DataAdapter.Fill將根據(jù)主鍵匹配新的行,同時從數(shù)據(jù)庫取值運用到已存在的行。除非已刷新行在再次刷新前被修改,否者它的RowState將會被設置為UnChanged。注意的是如果DataTable沒有設置主鍵,你的DataSet有可能出現(xiàn)重復的值。如果你想從數(shù)據(jù)庫刷新一個表并保留任何表中行的更改,那么你就要首先填充一個新表,然后利用preserveChanges等于true來合并那個DataTable到你的DataSet中去。

??? J.在DataSet中搜索數(shù)據(jù)

??????? 當你在一個DataSet中查詢特殊標準的行時,利用索引查詢將會增加你的查詢性能。當你給一個DataTable設計主鍵時,索引同時也創(chuàng)建了。當你為一個DataTable創(chuàng)建DataView時,索引也同時創(chuàng)建了。以下是使用索引查詢的一些情況:

??? ??? I.如果查詢與DataTable中標識主鍵的列順序相反,使用DataTable.Rows.Find代替DataTable.Select;

??????? II.如果查詢包括無主鍵的列,你可以使用DataView為數(shù)據(jù)的多重查詢改善性能。當你在DataView中使用排序時,查詢的同時就會創(chuàng)建一個索引。DataView使用Find和FindRows方法查詢DataTable中的數(shù)據(jù);

??????? IV.假如你不需要表的排序視圖,你也可以利用DataView為DataTable創(chuàng)建一個索引查詢。注意的是這僅僅在你執(zhí)行多重查詢時才有優(yōu)勢,如果你只是執(zhí)行一個簡單查詢,使用此方法將會降低你的查詢效率。

??? K.DataView的結(jié)構(gòu)

??????? 前面也講過,在給DataTable創(chuàng)建DataView和Sort、RowFilter或者RowStateFilter屬性發(fā)生更改的同時潛在的也給DataTable創(chuàng)建了索引。創(chuàng)建DataView對象時,如果Sort、RowFilter和RowStateFilter屬性也同時指定,那么索引將只創(chuàng)建一次;如果創(chuàng)建一個空的DataView,那么索引至少被創(chuàng)建兩次。

??? L.頁面調(diào)度

??????? ADO.NET使你可以很清楚地控制從你的數(shù)據(jù)庫返回什么樣的數(shù)據(jù)和有多少數(shù)據(jù)存儲到一個DataSet。以下沒有單一的介紹調(diào)度一個查詢結(jié)果,但是當你設計你的應用程序時應該考慮到以下情況:

??????? I.避免在使用DataAdapter.Fill時,在startRecord和maxRecords值上溢出。

??????? II.解決這類問題的辦法是使用WHERE語句、ORDER BY語句和TOP斷言。

??????? III.還有一種解決辦法是使用TOP斷言和嵌套的SELECT聲明。比如如下代碼:

???? SELECT TOP 10 * FROM

(SELECT TOP 30 * FROM Customers ORDER BY Id ASC) AS Table1 ORDER BY Id DESC

IV.如果你的日期不是經(jīng)常改變,你可以使用DataSet的存儲功能改善執(zhí)行性能,比如你可以存儲相當10頁的數(shù)據(jù)到你的DataSet,然后當用戶訪問超過在存儲區(qū)的FirstPage和LastPage時才查詢數(shù)據(jù)庫以獲得新的數(shù)據(jù)。

??? M.有計劃地填充DataSet

??????? 當使用數(shù)據(jù)填充DataSet時,DataAdapter.Fill方法使用DataSet已有的計劃和SelectCommand返回的數(shù)據(jù)對DataSet進行填充。如果DataSet中沒有與之對應的表將會失敗,Fill創(chuàng)建一個表,默認情況下,Fill僅僅定義列和列的類型。你可以通過設置DataAdapter的MissingSchemaAction屬性重載默認的Fill方法。舉例,要使Fill方法創(chuàng)建表時總是包含主鍵信息、唯一約束、列屬性、是否允許空值、列的最大長度、只讀列和自動增量列,指定DataAdapter.MissingSchemaAction為MissingSchemaAction.AddWithKey。作為選擇,你也可以在調(diào)用DataAdapter.Fill之前調(diào)用DataAdpater.FillSchema來保證填充DataSet時計劃到位。調(diào)用FillSchema會給數(shù)據(jù)庫增加額外的負擔來輸出Schema信息,所以最好的建議是指定DataSet的計劃,或者在調(diào)用Fill之前設置DataAdapter的MissingSchemaAction。

??? N.使用CommandBuilder

??????? CommandBuilder自動地生成基于DataAdapter的SelectCommand的DataAdapter的InsertCommand、UpdateCommand和DeleteCommand屬性。提供SelectCommand執(zhí)行一個簡單的SELECT,以下信息介紹使用CommandBuilder的最佳處理。

??????? I.在設計階段不要使用CommandBuilder,否者產(chǎn)生DataAdapter Command屬性的進程將會受到干擾。如果你預先知道你的UPDATE、INSERT和DELETE聲明的內(nèi)容,你應該清楚地指定。一個最好的設計方案是為你的UPDATE、INSERT和DELETE創(chuàng)建存儲過程,并在DataAdapter的Command屬性中設置和使用它們。

??????? II.CommandBuilder使用SelectCommand決定其他Command屬性的值。如果DataAdapter的SelectCommand本身發(fā)生變化,應該使用RefreshSchema去刷新Command的屬性。

??????? III.只要DataAdapter的Command屬性為空,CommandBuilder就僅僅創(chuàng)建一個Command,即使你明確地指定Command的屬性值,CommandBuilder也不會重寫,所以如果你想創(chuàng)建一個Command并保留以前的屬性設置,那么就把Command的屬性設置為null。

??? O.SQL的批聲明和處理

??????? 很多的數(shù)據(jù)庫都支持在一條命令中使用綜合查詢或批處理或多條子命令。比如SQL Server中使用“;”。在一條命令中使用綜合的多重命令可以有效地減少與數(shù)據(jù)庫之間交互的次數(shù)并在你的應用程序中提高效率。比如在你的應用程序中使用批處理完成所有的刪除(delete)任務等等。

??????? 使用批處理確實提高了效率,但同時也在你的應用程序中管理更新DataSet數(shù)據(jù)時增加了復雜性。要使得復雜性變簡單化,你就要在你的DataSet中為每個DataTable創(chuàng)建一個DataAdapter。

??? P.使用多個表填充一個DataSet

??????? 如果你是用批處理從多個表返回數(shù)據(jù)并把這些數(shù)據(jù)填充到一個DataSet,fill方法將會使用第一個表的表名命名第一個表,以后的表命名將會采用在第一個表的表名基礎上加上一個遞增的數(shù)字。舉例,下面的代碼將逐步說明fill方法的工作原理:

??????? ‘Visual Basic

??????? Dim da As SqlDataAdapter = New SqlDataAdapter(“select * from customers;select * from orders;”,myConnection)

??????? Dim ds As DataSet = New DataSet()

??????? da.fill(ds,”customers”)

??????? ‘C#

??????? SqlDataAdapter da = new SqlDataAdapter(“select * from customers;select * from orders;”,myConnection);

??????? DataSet ds = new DataSet();

??????? da.fill(ds,”customers”);

??????? 如上面代碼所示,customers表數(shù)據(jù)將會存放在一個命名為customers的DataTable中,而orders表數(shù)據(jù)將會放在一個命名為customers1的DataTable中。當然你也可以在數(shù)據(jù)填充結(jié)束后很容易地修改customers1表屬性(TableName)為orders。然而,在以后的數(shù)據(jù)填充時,只會影響customers表中數(shù)據(jù),而orders表將會忽略并同時創(chuàng)建一個新的命名為customers1的表。要解決這個問題,你就要在customers1和orders之間建立一個DataTableMapping映射。其他表也如此。舉例說明:

??????? ‘Visual Basic

Dim da As SqlDataAdapter = New SqlDataAdapter("SELECT * FROM Customers; SELECT * FROM Orders;", myConnection)

da.TableMappings.Add("Customers1", "Orders")

Dim ds As DataSet = New DataSet()

da.Fill(ds, "Customers")

‘C#

SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Customers; SELECT * FROM Orders;", myConnection);

da.TableMappings.Add("Customers1", "Orders");

DataSet ds = new DataSet();

da.Fill(ds, "Customers");

??? Q.使用DataReader

??????? 下面是使用DataReader的一些技巧和一些問題的回答:

??????? I.在使用相關Command訪問任何輸出參數(shù)之前必須關閉DataReader;

??????? II.在讀取數(shù)據(jù)結(jié)束后應當關閉DataReader。如果你的Connection僅僅是用來返回DataReader,那么在關閉DataReader之后你也應該立即關閉它。另外一個關閉Connection的方法是傳遞CommandBehavior.CloseConnection給ExecuteReader方法。此方法在你從一個方法中返回DataReader并且對這個DataReader沒有關閉控制權或者關聯(lián)的連接時使用時非常有用的。

??????? III.DataReader是為已連接的數(shù)據(jù)存取設計;

??????? IV.使用GetString、GetInt32等返回特殊數(shù)據(jù)類型數(shù)據(jù);

??????? V.一個連接只允許使用一個DataReader。在ADO中,如果你只創(chuàng)建一個連接并使用兩個recordsets,一個只讀游標和一個只進游標,但實際上,ADO已經(jīng)為你創(chuàng)建了一個隱式的連接,并在不用的時候隱式地關閉它。ADO.NET中是不行的,你必須為每個DataReader創(chuàng)建一個Connection,這也是為了讓你在使用Connection時給予更多的控制信息。

??????? VI.默認下,DataReader每次讀取時把行中所有的數(shù)據(jù)裝載到內(nèi)存中。并允許你隨機存取當前行中數(shù)據(jù)。如果隨即存取沒有必要(沒有必要把所有數(shù)據(jù)都裝載到內(nèi)存),并想提高執(zhí)行效率,給ExecuteReader方法傳遞CommandBehavior.SequentialAccess,這樣就會改變DataReader的默認動作為僅僅裝載請求的數(shù)據(jù)到內(nèi)存。注意的是這種方法要求你順序地存取行中列數(shù)據(jù),一旦你略過某一列,以后你將再不會讀取到該列的數(shù)據(jù)。

??????? VII.如果當你在完成從一個DataReader讀取數(shù)據(jù)后,仍然還有大量未讀不需要的數(shù)據(jù),這就要在調(diào)用DataReader的Close命令之前調(diào)用Cancel命令。調(diào)用DataReader的Close命令會導致把不需要的數(shù)據(jù)裝載進來并在關閉游標之前清空數(shù)據(jù)。而調(diào)用Cancel命令就會丟棄這部分數(shù)據(jù),從而DataReader在關閉之前就不會讀取它們。如果你正在從你的命令返回輸出參數(shù),調(diào)用Cancel命令同樣會丟棄它們。如果你需要讀取任何輸出參數(shù),你就不要使用Cancel,而直接使用Close。

??? R.BLOBs對象

??????? 當你使用DataReader讀取二進制數(shù)據(jù)時,你應該傳遞CommandBehavior.SequentialAccess給ExecuteReader方法調(diào)用。因為DataReader的默認情況是每次讀取數(shù)據(jù)時把每行中所有的數(shù)據(jù)都存儲到內(nèi)存,而二進制數(shù)據(jù)又非常的大,結(jié)果就會使大量的內(nèi)存空間被一個單一的BLOB占用。SequentialAccess使得你的DataReader默認行為為僅讀取需要的數(shù)據(jù)。然后你就可以使用GetBytes或者GetChars決定一次讀取多少數(shù)據(jù)。

??????? 記住的是使用SequentialAccess后,你不能次序顛倒地訪問DataReader中不同的字段。就是說,如果你的查詢返回三列,其中第三列是BLOB數(shù)據(jù)類型,如果你想訪問第三列數(shù)據(jù),那么你就必須先訪問第一列,然后是第二列,再然后才是第三列的BLOB數(shù)據(jù)。這是因為此時返回的數(shù)據(jù)是有序的,而且一旦你跳過某一列,再回過頭來讀取這一列是不行的。

??? S.使用命令

??????? ADO.NET提供了執(zhí)行命令的幾種不同方法,同時也提供了優(yōu)化執(zhí)行命令的幾種不同參數(shù)。下面將要介紹的是選擇最佳執(zhí)行命令的技巧和改善一個可執(zhí)行命令的性能。

??????? I.OleDbCommand最佳實踐

??????? .NET 框架中各種數(shù)據(jù)提供者之間的執(zhí)行命令標準幾乎是一樣的。但是也有不同,下面是執(zhí)行OleDbCommand的一些技巧:

??????? ??? 使用CommandType.Text調(diào)用存儲過程,使用CommandType.StoredProcedure生成;

??????????? 確定設置OleDbParameter的類型、大小(如果要求)和精度(如果是數(shù)字或者小數(shù)),注意的是,如果你不明確設置OleDbParameter,OleDbCommand將會為你的執(zhí)行命令重新生成OleDbParameter。

??????? II.SqlCommand最佳實踐

??????????? 使用SqlCommand快速執(zhí)行存儲過程:如果你要調(diào)用一個存儲過程,指定SqlCommand的CommandType為存儲過程的CommandType。這樣在執(zhí)行命令時,就會提交此命令是調(diào)用存儲過程,從而達到快速執(zhí)行。

??????? III.使用已準備的方法

??????????? Command.Prepare方法優(yōu)化你的參數(shù)化執(zhí)行命令。Prepare結(jié)構(gòu)為多重調(diào)用最優(yōu)化指定命令。要使用Prepare,你首先得理解你的數(shù)據(jù)庫是怎樣相應Prepare調(diào)用。SQL Server 2000中,Command已經(jīng)被隱式優(yōu)化和Prepare不是必須的;在SQL Server7.0或其它數(shù)據(jù)庫中使用Prepare是有效的。

??????? IV.明確地指定計劃和元數(shù)據(jù)

??????????? ADO.NET中的很多對象都要推斷元數(shù)據(jù)信息,只要用戶不指定它,舉例如下:

??????????? 如果在DataSet中不存在,DataAdapter.Fill方法就會創(chuàng)建表和列信息;

??????????? CommandBuilder為獨立表的Select命令生成DataAdpater命令參數(shù);

??????????? CommandBuilder.DeriveParameters組裝一個命令對象的參數(shù)信息;

??????? 如果什么時候都使用上面講的方法,可能會降低執(zhí)行性能。推薦在設計階段和廣告段應用程序中使用。可能的情況下,一般都要指定計劃和元數(shù)據(jù)。這些包括指定DataSet的表和列、指定DataAdapter的Command屬性和指定Command的參數(shù)信息。

??????? V.ExecuteScalar和ExecuteNonQuery

??????????? 如果你想只返回一個簡單值,比如Count(*)、Sum(Price)或者Avg(Quantity),你可以使用ExecuteScalar,它幫助你一步到位得到你想要的值,從而避免使用DataReader的兩步計算(ExecuteReader+GetValue);

??????????? 當你不想返回行信息,比如修改數(shù)據(jù)(INSERT、UPDATE、DELETE)或者僅需要輸出參數(shù)或者返回值,使用ExecuteNonQuery,它去掉不必要的處理創(chuàng)建一個空的DataReader。

??????? VI.空值檢查

??????????? 如果在你的表中某列允許空值,你可以使用Where語句進行空值檢查,下面舉例說明:

??????? select * from customers where ((LastName=@LastName) or (LastName IS NULL and @LastName IS NULL))

??????????? 上面語句檢查了列是否為空和參數(shù)是否為空。

??????? VII.傳遞null參數(shù)值

??????????? 當你在命令中傳遞null參數(shù)值給數(shù)據(jù)庫時,你不能使用null(Nothing在vb中),應該使用DBNull.Value。舉例:

??????? ‘vb

??????? Dim param As SqlParameter = New SqlParameter(“@Name”,SqlDbType.NVarChar,20)

??????? param.Value = DBNull.Value

??????? ‘C#

??????? SqlParameter param = new SqlParameter(“@Name”,SqlDbType.NVarChar,20);

??????? param.Value = DBNull.Value;

??????? VIII.使用事務處理

??????????? ADO.NET中的事務處理模型已經(jīng)改變,在ADO中,一旦StartTransaction被調(diào)用,任何事務下的更新都被認為是事務的一部分。然而,在ADO.NET中,當Connection.BeginTransaction被調(diào)用,返回一個命令關聯(lián)的事務對象(事務屬性是由命令的事務屬性指定的)。這樣保證讓你在一個Connection中執(zhí)行多個事務。如果命令的Command.Transaction屬性與開始的事務不一致,命令就不會完成并拋出錯誤。

??? ??? IX.使用Connections

??????????? 高效率的應用程序應該使用最少的時間與數(shù)據(jù)庫建立連接,比如使用Connection Pooling等。下面將介紹如何使用ADO.NET建立高效率應用的一些數(shù)據(jù)庫方面的技巧。

??????? Connection Pooling

??????????? 在SQL Server、OLE DB和.NET框架結(jié)構(gòu)中的Data Provider中,都提供了隱式的連接池連接支持。你可以在ConnectionString中指定不同的參數(shù)值控制連接池的行為。比如下面的例子使OLE DB的連接池無效并自動地進行事務處理:

??????? Provider=SQLOLEDB;OLE DB Services=-4;Data Source=localhost;Integrated Security=SSPI;

??????????? 在SQL Server.NET Data Provider中提供了以下參數(shù)設置控制連接池的行為:Connection Lifttime、Connection Reset、Enlist、Max Pool Size、Min Pool Size和Pooling。

??????? 使用DataAdapter最優(yōu)化連接

??????????? 使用DataAdpater的Fill和Update方法時會自動地打開相應的連接。如果Fill或者Update打開一個連接,在它操作完成后它會關閉此連接。最好的執(zhí)行方式是在你需要的時候才建立連接。同時減少多個操作時打開和關閉連接的次數(shù)。

??????????? 推薦你在僅僅執(zhí)行一個Fill或者Update時,允許Fill或者Update方法隱式地打開和關閉連接;如果你要執(zhí)行多個Fill或者Update,建議你顯式地建立連接、執(zhí)行Fill或者Update操作然后顯式地關閉連接。

??????????? 額外地,在我們執(zhí)行事務處理時,在開始事務之前應該顯式地建立連接,并在事務結(jié)束后顯式地關閉連接。舉例:

‘Visual Basic

Public Sub RunSqlTransaction(da As SqlDataAdapter, myConnection As SqlConnection, ds As DataSet)

?myConnection.Open()

?Dim myTrans As SqlTransaction = myConnection.BeginTransaction()

?myCommand.Transaction = myTrans

?Try

??? da.Update(ds)

??? myTrans.Commit()

??? Console.WriteLine("Update successful.")

?Catch e As Exception

??? Try

????? myTrans.Rollback()

??? Catch ex As SqlException

????? If Not myTrans.Connection Is Nothing Then

??????? Console.WriteLine("An exception of type " & ex.GetType().ToString() & _

????????????????????????? " was encountered while attempting to roll back the transaction.")

????? End If

??? End Try

??? Console.WriteLine("An exception of type " & e.GetType().ToString() & " was encountered.")

??? Console.WriteLine("Update failed.")

?End Try

?myConnection.Close()

End Sub

‘C#

public void RunSqlTransaction(SqlDataAdapter da, SqlConnection myConnection, DataSet ds)

{

?myConnection.Open();

?SqlTransaction myTrans = myConnection.BeginTransaction();

?myCommand.Transaction = myTrans;

?try

?{

??? da.Update(ds);

??? myCommand.Transaction.Commit();

??? Console.WriteLine("Update successful.");

?}

?catch(Exception e)

?{

??? try

??? {

????? myTrans.Rollback();

??? }

??? catch (SqlException ex)

??? {

????? if (myTrans.Connection != null)

????? {

??????? Console.WriteLine("An exception of type " + ex.GetType() +

????????????????????????? " was encountered while attempting to roll back the transaction.");

????? }

??? }

??? Console.WriteLine(e.ToString());

??? Console.WriteLine("Update failed.");

?}

?myConnection.Close();

}

??????? X.總是關閉Connections和DataReaders

??????????? 在你使用完Connection或者DataReader對象后,你應該明確地關閉它們。系統(tǒng)中的碎片整理程序只是在最后需要的時候才進行整理,而一些很耗資源的連接還得由你自己來釋放。同時如果你不明確地關閉連接,此連接就有可能不返回連接池,除非連接池的Max Pool Size已經(jīng)達到并且此連接還仍然有效。

??????????? 注意:在你的類的Finalize方法中不要使用Close或者Dispose運用到一個Connection或者一個DataReader或者任何被管理對象上。在一個Finalizer中,僅僅釋放你的類直接擁有的無法管理的資源。如果你的類不擁有任何無法管理的資源,就不要在你的類使用Finalize方法。

??????? XI.在C#中使用Using聲明

??????????? 在C#中,一個非常便利的保證關閉你使用過的Connection和DataReader對象的方法是使用Using聲明。當對象超出了它的使用范圍,Using聲明就會自動地釋放該對象。舉例:

‘C#

string connString = "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;";

using (SqlConnection conn = new SqlConnection(connString))

{

?SqlCommand cmd = conn.CreateCommand();

?cmd.CommandText = "SELECT CustomerId, CompanyName FROM Customers";

?

?conn.Open();

?using (SqlDataReader dr = cmd.ExecuteReader())

?{

??? while (dr.Read())

????? Console.WriteLine("{0}"t{1}", dr.GetString(0), dr.GetString(1));

?}

}

??????????? Using聲明在Visual Basic.Net中不可用。

??????? XII.避免訪問OleDbConnection.State屬性

??????????? 如果你需要經(jīng)常檢查State屬性,最好在OleDbConnection上監(jiān)聽StateChange事件。下面的代碼演示當OleDbConnection.State發(fā)生變化時使用StateChange向控制臺發(fā)送一條消息:

‘Visual?Basic

AddHandler nwindConn.StateChange, New StateChangeEventHandler(AddressOf OnStateChange)

Protected Shared Sub OnStateChange(sender As Object, args As StateChangeEventArgs)

?Console.WriteLine("The current Connection state has changed from {0} to {1}.", _

??????????????????? args.OriginalState, args.CurrentState)

End Sub

‘C#

nwindConn.StateChange?+= new StateChangeEventHandler(OnStateChange);

protected static void OnStateChange(object sender, StateChangeEventArgs args)

{

?Console.WriteLine("The current Connection state has changed from {0} to {1}.",

??????????????????? args.OriginalState, args.CurrentState);

}

??? T.與XML結(jié)合

??????? ADO.NET在DataSet中提供對XML的廣泛支持,同時在SQL Server2000或以后版本中的XML功能性擴展也能在ADO.NET中得到充分運用。你可以使用SQLXML訪問在SQL Server2000和以后版本中提供的XML功能性擴展。下面是使用XML和ADO.NET的一些技巧信息。

??? ??? I.DataSet和XML

??????? DataSet和XML的完美整合,可以使你完成以下事情:

??????????? 從XSD計劃中載入一個DataSet的計劃或相關結(jié)構(gòu);

??????????? 下面的例子說明一個XSD文件的結(jié)構(gòu),其中MyDataSet就是我們的DataSet元素,它下面包含一個customers復合類型元素,有了它我們就可以映射創(chuàng)建一個這樣的表:Customers (CustomerID,CompanyName,Phone),同時也定義我們的DataSet的計劃或者結(jié)構(gòu):

<xs:schema id="SomeID"

???????????? xmlns=""

???????????? xmlns:xs="http://www.w3.org/2001/XMLSchema"

???????????? xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">

??? <xs:element name="MyDataSet" msdata:IsDataSet="true">

????? <xs:complexType>

???? ???<xs:choice maxOccurs="unbounded">

????????? <xs:element name="customers" >

??????????? <xs:complexType >

????????????? <xs:sequence>

??????????????? <xs:element name="CustomerID" type="xs:integer"

???????????????????????????? minOccurs="0" />

??????? ????????<xs:element name="CompanyName" type="xs:string"

???????????????????????????? minOccurs="0" />

??????????????? <xs:element name="Phone" type="xs:string" />

????????????? </xs:sequence>

??????????? </xs:complexType>

?????????? </xs:element>

??????? </xs:choice>

????? </xs:complexType>

??? </xs:element>

?</xs:schema>

??????????? 從XML文件中載入一個DataSet的內(nèi)容;

??????????? 要從XML文件填充DataSet的內(nèi)容,請使用DataSet對象的ReadXml方法。下面的例子說明如何從一個XML文件讀取數(shù)據(jù)到一個DataSet:

‘Visual?Basic

Dim myDS As DataSet = New DataSet

myDS.ReadXml("input.xml", XmlReadMode.ReadSchema)

‘C#

DataSet myDS = new DataSet();

myDS.ReadXml("input.xml", XmlReadMode.ReadSchema);

??????????? 當沒有提供計劃時從一個XML文件的內(nèi)容中推斷一個DataSet的計劃;

??????????? 要從一個XML文件載入DataSet的計劃信息,你可以使用DataSet對象的ReadXmlSchema方法。如果沒有提供計劃,你還可以使用InferXmlSchema從XML文件推斷DataSet的計劃,下面的例子介紹如何通過InferXmlSchema從一個XML文件推斷出DataSet的計劃:

‘Visual?Basic

Dim myDS As DataSet = New DataSet

myDS.InferXmlSchema("input_od.xml", New String[] {"urn:schemas-microsoft-com:officedata"})

‘C#

DataSet myDS = new DataSet();

myDS.InferXmlSchema("input_od.xml", new string[] "urn:schemas-microsoft-com:officedata");

??????????? 象XSD格式計劃一樣寫一個DataSet的計劃;

??????????? 下面的例子展示如何通過ReadXmlSchema從一個XSD文件載入DataSet的計劃:

‘Visual?Basic

Dim myDS As DataSet = New DataSet

myDS.ReadXmlSchema("schema.xsd")

‘C#

DataSet myDS = new DataSet();

myDS.ReadXmlSchema("schema.xsd");

??????????? 象XML格式文件一樣讀寫一個DataSet的內(nèi)容。

??????????? 利用DiffGrams從DataSet中讀寫內(nèi)容,下面的例子顯示在提交更改之前更新表中一行數(shù)據(jù)的結(jié)果,其中CustomerID為ALFKI的那一行數(shù)據(jù)被修改但是還沒有更新:

<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">

?<CustomerDataSet>

??? <Customers diffgr:id="Customers1" msdata:rowOrder="0" diffgr:hasChanges="modified">

????? <CustomerID>ALFKI</CustomerID>

????? <CompanyName>New Company</CompanyName>

??? </Customers>

??? <Customers diffgr:id="Customers2" msdata:rowOrder="1" diffgram:hasErrors="true">

????? <CustomerID>ANATR</CustomerID>

????? <CompanyName>Ana Trujillo Emparedados y helados</CompanyName>

??? </Customers>

??? <Customers diffgr:id="Customers3" msdata:rowOrder="2">

????? <CustomerID>ANTON</CustomerID>

????? <CompanyName>Antonio Moreno Taquerí-a</CompanyName>

??? </Customers>

??? <Customers diffgr:id="Customers4" msdata:rowOrder="3">

????? <CustomerID>AROUT</CustomerID>

????? <CompanyName>Around the Horn</CompanyName>

??? </Customers>

?</CustomerDataSet>

?<diffgr:before>

??? <Customers diffgr:id="Customers1" msdata:rowOrder="0">

????? <CustomerID>ALFKI</CustomerID>

????? <CompanyName>Alfreds Futterkiste</CompanyName>

??? </Customers>

?</diffgr:before>

?<diffgr:errors>

??? <Customers diffgr:id="Customers2" diffgr:Error="An optimistic concurrency violation has occurred for this row."/>

?</diffgr:errors>

</diffgr:diffgram>

??????? 注意:你可以在你的DataSet中使用XPath查詢和XSLT轉(zhuǎn)換來同步運用XML的功能性,或者提供一個相關的視圖,或者創(chuàng)建一個XML文檔數(shù)據(jù)的一個副本。

??? ??? II.計劃接口

??????????? 當你從一個XML文件載入一個DataSet時,你可以從XSD計劃載入DataSet的計劃,或者你可以在載入數(shù)據(jù)之前預先確定表和列。如果這里沒有XSD計劃或者你又不知道那個表和列是XML文件內(nèi)容確定的,那么你可以使用基于XML文檔結(jié)構(gòu)推斷計劃。

??????????? 計劃接口是一個很有用的移植工具,但是它應該限制在設計階段的應用程序中,僅僅因為以下幾點:

??????????? 推斷計劃將會提出額外的處理從而影響應用程序性能的提高;

??????????? 所有的列將會是一個數(shù)據(jù)類型:string;

??????????? 推斷過程具有不確定性。那就是說,它是基于XML文件的,而不是基于有意的計劃。

??????? III.SQL SERVER 的FOR XML查詢

??????????? 如果你想返回如SQL SERVER的FOR XML查詢結(jié)果,你可以用SQL Server.NET Data Provider直接使用SqlCommand.ExecuteXmlReader方法創(chuàng)建一個XmlReader。

??????? IV.SQLXML管理類

??????????? 在.NET框架中SQLXML管理類使用Microsoft.Data.SqlXml命名空間。它使得你可以執(zhí)行Xpath查詢和XML模板文件,如同運用XSLT轉(zhuǎn)換數(shù)據(jù)一樣。最新版本是SQLXML3.0。

??? U.更多有用技巧

??????? I.避免自動增量值沖突

??????????? 像大多數(shù)數(shù)據(jù)庫一樣,DataSet讓你在增加新的數(shù)據(jù)時標識為自動增量的列自動填充增量值。使用自動增量時,應當避免本地DataSet的增量值與數(shù)據(jù)庫的增量值相沖突。要避免這種情況,推薦在數(shù)據(jù)庫和DataSet同時使用自動增量時,在你的DataSet中創(chuàng)建AutoIncrementStep為-1和AutoIncrementSeed為0的自動增量列,同時保證你的數(shù)據(jù)庫中的列從1開始正方向遞增。這樣就保證一個負方向的增量不會與一個正方向的增量相沖突。另外一種方法是使用Guid代替自動增量。在DataSet中產(chǎn)生的Guid永遠不會與數(shù)據(jù)庫中產(chǎn)生的Guid一樣。如果你的自動增量列只是簡單地用作唯一值,并且不表示任何含義,建議你使用Guids代替自動增量。它們是唯一的并避免使用自動增量產(chǎn)生的額外工作。

??????? II.處理樂觀并發(fā)錯誤

??????????? 因為DataSet與數(shù)據(jù)庫是分離的,所以你應該在你的應用程序中避免當多個客戶更新數(shù)據(jù)庫數(shù)據(jù)時發(fā)生沖突。這里有幾種處理樂觀并發(fā)錯誤的解決方案。一是在你的表中增加一個時間戳列。二是校驗一行中所有列的數(shù)據(jù)是否與你在SQL聲明中使用Where子句找到的數(shù)據(jù)靜態(tài)匹配。下面的例子說明如何使用where條件處理樂觀并發(fā)錯誤:

‘Visual?Basic

?Dim nwindConn As SqlConnection = New SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind")

?Dim custDA As SqlDataAdapter = New SqlDataAdapter("SELECT CustomerID, CompanyName FROM Customers ORDER BY CustomerID", nwindConn)

?' The Update command checks for optimistic concurrency violations in the WHERE clause.

?custDA.UpdateCommand = New SqlCommand("UPDATE Customers (CustomerID, CompanyName) VALUES(@CustomerID, @CompanyName) " & _

??????????????????????????????????????? "WHERE CustomerID = @oldCustomerID AND CompanyName = @oldCompanyName", nwindConn)

?custDA.UpdateCommand.Parameters.Add("@CustomerID", SqlDbType.NChar, 5, "CustomerID")

?custDA.UpdateCommand.Parameters.Add("@CompanyName", SqlDbType.NVarChar, 30, "CompanyName")

?' Pass the original values to the WHERE clause parameters.

?Dim myParm As SqlParameter

?myParm = custDA.UpdateCommand.Parameters.Add("@oldCustomerID", SqlDbType.NChar, 5, "CustomerID")

?myParm.SourceVersion = DataRowVersion.Original

?myParm = custDA.UpdateCommand.Parameters.Add("@oldCompanyName", SqlDbType.NVarChar, 30, "CompanyName")

?myParm.SourceVersion = DataRowVersion.Original

?' Add the RowUpdated event handler.

?AddHandler custDA.RowUpdated, New SqlRowUpdatedEventHandler(AddressOf OnRowUpdated)

?Dim custDS As DataSet = New DataSet()

?custDA.Fill(custDS, "Customers")

?' Modify the DataSet contents.

?custDA.Update(custDS, "Customers")

?Dim myRow As DataRow

?For Each myRow In custDS.Tables("Customers").Rows

??? If myRow.HasErrors Then Console.WriteLine(myRow(0) & vbCrLf & myRow.RowError)

?Next

Private Shared Sub OnRowUpdated(sender As object, args As SqlRowUpdatedEventArgs)

?If args.RecordsAffected = 0

??? args.Row.RowError = "Optimistic Concurrency Violation Encountered"

??? args.Status = UpdateStatus.SkipCurrentRow

?End If

End Sub

‘C#

?SqlConnection nwindConn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind");

?SqlDataAdapter custDA = new SqlDataAdapter("SELECT CustomerID, CompanyName FROM Customers ORDER BY CustomerID", nwindConn);

?// The Update command checks for optimistic concurrency violations in the WHERE clause.

?custDA.UpdateCommand = new SqlCommand("UPDATE Customers (CustomerID, CompanyName) VALUES(@CustomerID, @CompanyName) " +

??????????????????????????????????????? "WHERE CustomerID = @oldCustomerID AND CompanyName = @oldCompanyName", nwindConn);

?custDA.UpdateCommand.Parameters.Add("@CustomerID", SqlDbType.NChar, 5, "CustomerID");

?custDA.UpdateCommand.Parameters.Add("@CompanyName", SqlDbType.NVarChar, 30, "CompanyName");

?// Pass the original values to the WHERE clause parameters.

?SqlParameter myParm;

?myParm = custDA.UpdateCommand.Parameters.Add("@oldCustomerID", SqlDbType.NChar, 5, "CustomerID");

?myParm.SourceVersion = DataRowVersion.Original;

?myParm = custDA.UpdateCommand.Parameters.Add("@oldCompanyName", SqlDbType.NVarChar, 30, "CompanyName");

?myParm.SourceVersion = DataRowVersion.Original;

?// Add the RowUpdated event handler.

?custDA.RowUpdated += new SqlRowUpdatedEventHandler(OnRowUpdated);

?DataSet custDS = new DataSet();

?custDA.Fill(custDS, "Customers");

?// Modify the DataSet contents.

?custDA.Update(custDS, "Customers");

?foreach (DataRow myRow in custDS.Tables["Customers"].Rows)

?{

??? if (myRow.HasErrors)

????? Console.WriteLine(myRow[0] + ""n" + myRow.RowError);

?}

protected static void OnRowUpdated(object sender, SqlRowUpdatedEventArgs args)

{

?if (args.RecordsAffected == 0)

?{

??? args.Row.RowError = "Optimistic Concurrency Violation Encountered";

??? args.Status = UpdateStatus.SkipCurrentRow;

?}

}

??????? III.協(xié)作設計

??????????? 在你寫期間,你應當鎖定DataSet。

??????? IV.僅當需要的時候才使用COM對象訪問ADO

??????????? ADO.NET設計為大量應用程序最好的解決方案。然而一些應用程序需要只有ADO對象才能提供的功能,比如ADOMD。這種情況下可以使用COM對象訪問ADO,注意的是使用COM對象訪問ADO數(shù)據(jù)會影響應用程序的執(zhí)行效率。所以在設計應用程序時,首先應該考慮在使用COM對象訪問ADO數(shù)據(jù)之前,看看ADO.NET是否就滿足你的設計要求。

??? V.ADO.NET和ADO的比較

??????? I.ADO.NET在ADO設計模型的基礎上演變和發(fā)展而來,它并不取代COM程序員的ADO,更多地,它是為.NET程序員訪問相關數(shù)據(jù)源、XML和應用程序數(shù)據(jù)設計。ADO.NET支持多樣化的發(fā)展要求,包括創(chuàng)建數(shù)據(jù)庫客戶端和供應用程序、工具、語言、WEB瀏覽器等使用的中間層業(yè)務對象。ADO.NET與ADO有許多相似的地方。

??????? II.ADO為COM程序員提供了高效的、強大的與數(shù)據(jù)庫打交道的各種接口。ADO能得到廣泛的運用是因為它支持任何的自動化控制語言(比如VC、VB和腳本語言等)的調(diào)用。ADO基礎上升級而來的ADO.NET提供更好的交互平臺和可升級的數(shù)據(jù)訪問。在ADO.NET中創(chuàng)建一個新的數(shù)據(jù)訪問API集能提供較之于ADO接口幾個優(yōu)越的地方,如下所述:

??????????? 改進了與XML的結(jié)合

??????????? 隨著XML在應用程序中扮演著越來越重要的角色,與XML結(jié)合的ADO.NET就應運而生。為了持續(xù)和裝載數(shù)據(jù)以及數(shù)據(jù)的XML格式,ADO.NET依賴XML在多層之間或客戶機之間遠程傳遞數(shù)據(jù)。ADO.NET中使用的特殊XML表述形式提供在任何網(wǎng)絡中十分便利地傳輸數(shù)據(jù)的方法,包括數(shù)據(jù)安全邊界。同時,ADO.NET使用XML工具執(zhí)行確認、分級查詢和數(shù)據(jù)和數(shù)據(jù)之間的轉(zhuǎn)換。

??????????? 綜合.NET框架

??????????? ADO結(jié)構(gòu)如Recordset并不使用常見的設計結(jié)構(gòu),相反它模擬成一種數(shù)據(jù)導向。舉例,ADO中的用來導航和得到數(shù)據(jù)的游標,它的功能性就與其它的比如數(shù)組和集合數(shù)據(jù)結(jié)構(gòu)不同。然而,在ADO.NET中,因為存儲的數(shù)據(jù)能通過公共的.NET框架結(jié)構(gòu)暴露,包括數(shù)組和集合,所以你可以使用一些公共的方法與你的相關數(shù)據(jù)打交道。

??????????? 改良對離散業(yè)務模型的支持

??????????? ADO使用Recordset提供有限的對離散訪問的支持。ADO.NET介紹一個新的對象DataSet,它作為相關數(shù)據(jù)的一個公共的、存儲的表現(xiàn)形式,在任何時候都被設計為離散的,它與外部數(shù)據(jù)并不保持持久的連接,它是包裝、存儲、交換、延續(xù)和裝載數(shù)據(jù)的好方法。也就是說任何對數(shù)據(jù)的操作都是在本地進行,而不直接與真實的數(shù)據(jù)庫打交道。

??????????? 數(shù)據(jù)訪問行為的控制是清楚的

??????????? ADO中包括在應用程序中并不總是要求和指定的隱含行為會限制應用程序的性能。而在ADO.NET中提供良好的定義和預先的行為、執(zhí)行和語義要素組件使得你可以在一個高優(yōu)化的方式下定位到一個普通的情節(jié)上。

??????????? 改善設計階段的支持

??????????? ADO源自執(zhí)行階段隱含的數(shù)據(jù)信息,而這種信息是基于花費昂貴代價才獲得的元數(shù)據(jù)。在ADO.NET中的元數(shù)據(jù)只是在設計階段起一個杠桿作用,從而提供執(zhí)行階段更好的性能和更好的穩(wěn)定性。

??????? III.ADO設計

??????????? 為了更好地理解ADO.NET模型和設計思想,回顧一下ADO的概念是有用的。ADO使用一個單一的對象Recordset與所有數(shù)據(jù)類型打交道。Recordset被用來處理從數(shù)據(jù)庫返回的只進流數(shù)據(jù)、翻卷服務器上數(shù)據(jù)或者翻卷一批存儲結(jié)果集。數(shù)據(jù)上的改變會立即運用到數(shù)據(jù)庫上或運用到使用樂觀查詢和更新操作的一批數(shù)據(jù)上。當你創(chuàng)建一個Recordset時你就明確了你所作的任務,Recordset結(jié)果行為的改變主要取決于你要求的Recordset參數(shù)。因為ADO使用一個單一的能在很多場合使用的Recordset對象,這使得你的應用程序中的對象模型很簡單。然而,也很難寫一個公用的、可預言的和最優(yōu)化的代碼,那是因為行為、執(zhí)行和一個單一對象描述的語義要得到改變很大程度上取決于對象是如何創(chuàng)建和對象訪問的是什么數(shù)據(jù)。

??????? IV.ADO.NET設計

??????????? ADO.NET是考慮到開發(fā)者在訪問和使用數(shù)據(jù)時共同面對的任務和問題而設計。寧可使用一個單一對象執(zhí)行大量任務,還不如如ADO.NET中指定每個對象的功能性因素去完成對應的每個任務。ADO中的Recordset功能性被分解成ADO.NET中以下的幾個清楚對象:DataReader,提供快速的、只進的和只讀的訪問去查詢結(jié)果;DataSet,存儲數(shù)據(jù);DataAdapter,在DataSet和數(shù)據(jù)源之間架起一道橋梁;ExecuteNonQuery,不返回行;ExecuteScalar,返回一個單一值而不是一個行集。下面是一些詳細說明:

??????????? 只進、只讀數(shù)據(jù)流

??????????? 應用程序,特別是中間層應用程序,經(jīng)常要程序化地處理一系列結(jié)果,要求在他們讀的時候沒有用戶交互和沒有更新或回滾結(jié)果。在ADO中,執(zhí)行這類數(shù)據(jù)時使用Recordset的只進游標和只讀鎖。在ADO.NET中,DataReader優(yōu)化了這種數(shù)據(jù)的執(zhí)行性能,它通過提供一個非緩沖、只進和只讀的數(shù)據(jù)流從數(shù)據(jù)庫得到數(shù)據(jù)。

??????????? 返回單一值

??????????? 在ADO中要得到一個單一值,你需要通過創(chuàng)建一個Recordset—〉讀取結(jié)果—〉得到單一值—〉關閉Recordset這樣一個過程。在ADO.NET中你就可以使用Command對象的ExecuteScalar方法不需要額外的操作來獲得單一值。

??????????? 離散數(shù)據(jù)訪問

??????????? ADO使用客戶端游標定位離散數(shù)據(jù)的訪問,而在ADO.NET中DataSet可以很清楚地實現(xiàn)離散數(shù)據(jù)的訪問。DataSet能從一個多樣的不同的數(shù)據(jù)源提供一個公有的、完全離散的數(shù)據(jù)表現(xiàn)形式,是因為DataSet是完全獨立于數(shù)據(jù)源的。它不管你數(shù)據(jù)是從數(shù)據(jù)庫來的,還是從XML文件來的,抑或是從應用程序中得到的。一個簡單的DataSet可以裝載從多個不同數(shù)據(jù)庫或非數(shù)據(jù)庫源的數(shù)據(jù)。然后使用DataRelation在多個表之間建立一個連接,盡管Recordset的MsDataShape提供者可以實現(xiàn)分級結(jié)構(gòu)查詢,但是DataSet提供更高的穩(wěn)定性處理離散數(shù)據(jù)。同時DataSet提供以XML文件格式在遠程客戶端和服務器之間傳輸數(shù)據(jù)。

??????????? 從數(shù)據(jù)庫得到數(shù)據(jù)和更新數(shù)據(jù)

??????????? ADO.NET提供更好的執(zhí)行階段性能和可見性。舉例,當使用ADO的Recordset對象進行批更新時,你必須為每個需要改變結(jié)果的行使用UPDATE、INSERT或DELETE聲明。ADO產(chǎn)生這些聲明,在執(zhí)行階段,是需要付出昂貴代價的獲得元數(shù)據(jù)的。而在ADO.NET中,指定UPDATE、INSERT或DELETE命令就如同自定義業(yè)務邏輯(比如一個存儲過程)一樣,你可以使用DataAdapter實現(xiàn)這一切。DataAdapter在DataSet和數(shù)據(jù)源之間架起一道橋梁。讓你在執(zhí)行階段就不是如ADO的Recordset一樣需要在數(shù)據(jù)源中收集元數(shù)據(jù)信息。從而改善應用程序的執(zhí)行性能。

??????? V.數(shù)據(jù)類型

??????????? 在ADO中,所有的結(jié)果返回一個Variant數(shù)據(jù)類型,在ADO.NET中,你可以得到列本身的數(shù)據(jù)類型。數(shù)據(jù)類型可以在System.Data.SqlTypes名稱空間定義。

??? W.有關ADO和ADO.NET的詳細介紹,請參考微軟上的資料:ADO.NET for the ADO Programmer

??? 總結(jié):

??? 通過本文,希望與大家共同交流和學習,有不當之處請大家指正,謝謝!


轉(zhuǎn)載于:https://www.cnblogs.com/feima-lxl/archive/2008/07/12/1241225.html

總結(jié)

以上是生活随笔為你收集整理的【转】 ADO.NET最佳实践的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

国产三级精品三级在线观看 | 91精品一区二区三区久久久久久 | 一级黄色网址 | 国产对白av | 黄色小网站在线观看 | 国产日韩精品久久 | 欧美日韩一区二区在线观看 | 国产麻豆精品一区 | 免费日韩电影 | wwwwww色| 丝袜美女在线 | 亚洲日本在线视频观看 | 婷婷丁香色综合狠狠色 | 91九色在线观看视频 | 天堂av网址 | 久久在线免费 | 中文字幕在线看视频国产中文版 | 日批视频国产 | 午夜性福利 | 麻花豆传媒mv在线观看网站 | 免费三级黄色片 | 狠狠网| 欧美经典久久 | 91视频 - 88av| 日韩免费一区二区 | 在线观看免费黄视频 | 欧美日韩在线免费观看视频 | 国产精品第54页 | 丝袜精品视频 | 免费久久久 | 九九热免费精品视频 | 激情五月开心 | 久久99亚洲精品久久久久 | 亚洲 欧美 国产 va在线影院 | 国产精品网址在线观看 | 国产精品黄色 | 精品在线你懂的 | 久久精品专区 | 中文字幕在线观看网址 | 日韩欧美高清一区二区三区 | 国产精品少妇 | 成片免费观看视频 | 黄色a一级片 | 91麻豆精品一区二区三区 | 国内精品久久久久影院一蜜桃 | 极品国产91在线网站 | 天天插天天操天天干 | 91色网址 | 99视频99 | 国产又黄又爽无遮挡 | 中文字幕在线观看免费观看 | 精品一区二区日韩 | 日韩精品免费在线视频 | 久久字幕 | 久久久久久久久久久精 | 天天干天天草天天爽 | 69视频网站 | 国产免费人成xvideos视频 | 正在播放国产一区二区 | 欧美精品久久久久久久久久 | 久久成人免费视频 | 日韩精品亚洲专区在线观看 | 激情电影影院 | 国产小视频91 | 黄色成人免费电影 | 国产成年免费视频 | 国产国产人免费人成免费视频 | 久久国产91| 激情久久久久久久久久久久久久久久 | 日韩中文字幕免费视频 | 最近在线中文字幕 | 亚洲午夜小视频 | 99精品一区二区三区 | av福利网址导航大全 | 国精产品一二三线999 | 日韩免费观看高清 | 一级久久久 | 国产精品久久久久久一区二区三区 | 天天躁日日躁狠狠躁 | 欧美日韩国产二区三区 | 欧美一区二区三区特黄 | 国产一区麻豆 | 99精品视频在线免费观看 | 区一区二区三在线观看 | 久久9999久久| 成人不用播放器 | 国产视频不卡一区 | 亚洲情婷婷 | 91成熟丰满女人少妇 | 天天天天天天操 | 日韩av高清 | 在线视频一二区 | 久久久久久久久久免费 | 在线国产激情视频 | 色视频在线观看免费 | 久久国产精品成人免费浪潮 | 日韩欧美一区二区在线播放 | 91女子私密保健养生少妇 | 97精品在线观看 | 日韩在线在线 | 色婷婷视频在线观看 | 美女国内精品自产拍在线播放 | 亚洲一区二区高潮无套美女 | 久久人人看 | 黄色av在 | 日韩特级黄色片 | 欧美一级性视频 | 久久高清免费 | 国产综合小视频 | 激情久久伊人 | 日韩欧美xxxx| 在线观看免费国产小视频 | 日日干夜夜操视频 | 色国产视频 | 亚洲另类视频在线观看 | 欧美最爽乱淫视频播放 | 日日夜夜天天久久 | 亚洲第一中文网 | 玖玖爱国产在线 | 国产日韩精品视频 | 日韩18p| 久久精品1区 | 国产中文在线字幕 | 911精品美国片911久久久 | 福利视频午夜 | 人人爽人人澡 | 国产私拍在线 | 精品久久久久久久久久岛国gif | 日韩欧美有码在线 | 中文网丁香综合网 | 日日夜夜免费精品 | 一级黄色大片在线观看 | 国产直播av | 在线看的av网站 | 69绿帽绿奴3pvideos | 欧美日韩综合在线观看 | 中文字幕欧美日韩va免费视频 | 日韩免费观看一区二区三区 | 午夜精品久久久久久久久久久久久久 | 久久久久女人精品毛片九一 | 欧美另类v | 久久久久免费 | 午夜国产影院 | 精品国产乱码久久久久久浪潮 | 91视频免费观看 | 成人高清av在线 | 日韩免费观看一区二区 | 国产成人精品免费在线观看 | 国产精品成人一区二区三区 | 97超碰人人 | 波多野结衣综合网 | 日韩高清在线一区二区三区 | 欧美 日韩精品 | 久久久精品网 | 日韩av电影免费在线观看 | 日本中文乱码卡一卡二新区 | 成人av影视在线 | 国产精品久久在线 | a午夜在线 | 4438全国亚洲精品在线观看视频 | 中文字幕在线免费97 | 国产色网站| 久久精品精品电影网 | 国产黄色播放 | 一级片免费观看视频 | 中文字幕色在线视频 | 日韩综合在线观看 | 欧美 日韩 性 | 久久精品国产精品亚洲精品 | 亚洲欧美日本国产 | www.黄色片网站 | 国产精品v欧美精品v日韩 | 国内亚洲精品 | 亚洲视频大全 | 久久精品看片 | 久久精品免费看 | 日韩丝袜在线观看 | 欧美一级电影在线观看 | 国产99久久九九精品免费 | 亚洲尺码电影av久久 | 日韩欧美xxx| 成年人免费看av | av一区二区三区在线 | 人人爽人人爱 | 国产一区在线免费 | 91高清免费看 | 精品欧美乱码久久久久久 | 麻豆视频免费入口 | 国产在线国产 | 久久免费电影 | 欧美精品久久久久久久免费 | 在线精品视频在线观看高清 | 国产亚洲精品久久久久久久久久 | 日韩精品久久久久久久电影99爱 | av成人免费在线看 | 久久 亚洲视频 | 久久久久久久久久久电影 | 在线免费观看av网站 | 国产精品高清在线观看 | 亚洲精品人人 | 中文字幕在线成人 | 97视频一区 | 久草青青在线观看 | 亚洲第一av在线播放 | 久草在线观 | 国产97免费 | 中文字幕一区二区在线播放 | 国产不卡毛片 | 韩日精品在线 | 91一区啪爱嗯打偷拍欧美 | 欧美一级艳片视频免费观看 | 99精品一级欧美片免费播放 | 黄色在线看网站 | 中文字幕精品一区久久久久 | 天堂成人在线 | 狠狠色综合网站久久久久久久 | 日本二区三区在线 | 五月天六月丁香 | 免费福利在线 | 九九免费观看全部免费视频 | 少妇搡bbbb搡bbb搡aa | 免费欧美高清视频 | 日韩高清不卡一区二区三区 | 亚洲女人天堂成人av在线 | 日韩欧美视频在线播放 | a在线免费 | 色偷偷中文字幕 | 伊人精品在线 | 精品久久久久久久久久久久 | 激情综合五月网 | 中文字幕在线观看免费高清电影 | 这里只有精彩视频 | 国产成人在线观看免费 | 日批视频在线 | 国产精品久久久久久久久婷婷 | 日日夜夜艹 | 在线看毛片网站 | 亚洲精品777 | 三级动态视频在线观看 | ,久久福利影视 | 在线免费观看国产精品 | 日韩精品久久久久久久电影竹菊 | 91色影院 | 97看片吧| 欧美精品小视频 | 日韩高清观看 | 免费视频区 | 成人h动漫精品一区二 | 伊人www22综合色 | 亚洲天堂自拍视频 | 日韩一区二区免费在线观看 | 三级黄色大片在线观看 | 日韩伦理一区二区三区av在线 | 国产区第一页 | 天天爱天天草 | 国产小视频福利在线 | 亚洲欧美国产视频 | 欧美性极品xxxx做受 | 99视频偷窥在线精品国自产拍 | 日韩在线三级 | 日韩免费视频 | 成人动漫精品一区二区 | 99久久精品日本一区二区免费 | 国外成人在线视频网站 | 天天狠狠操 | 美女视频黄色免费 | 激情文学综合丁香 | 97成人精品视频在线观看 | 欧美久久影院 | 国产精品刺激对白麻豆99 | 免费成人在线视频网站 | 天天天综合网 | 久久久久久久久电影 | 国产成人一区二区三区影院在线 | 色偷偷av男人天堂 | 日日碰夜夜爽 | 久精品视频免费观看2 | 日韩一二区在线 | 在线观看日韩免费视频 | 国产资源免费 | 天天激情在线 | 久久国产网站 | 天天射天天射天天 | 黄色一集片 | 亚洲激情中文 | 国产精品99免费看 | 国产五月色婷婷六月丁香视频 | 久久综合久色欧美综合狠狠 | 黄色av免费看 | 日本中文字幕观看 | 五月天六月婷 | 国产精品99久久久久久小说 | 97av在线视频 | 二区三区视频 | 888av | 友田真希av| 99精品免费久久久久久久久 | 久久久久久99精品 | 狠狠狠狠狠狠操 | 国产精品久久久久久久久久久免费看 | 久久久午夜精品福利内容 | 国产福利av在线 | 婷婷伊人综合亚洲综合网 | 亚洲午夜av久久乱码 | 日韩啪啪小视频 | 日韩av网址在线 | 免费亚洲精品视频 | 国产成人一区二区三区电影 | 亚洲精品国产品国语在线 | 国产精品手机看片 | 色国产视频 | 狠狠色香婷婷久久亚洲精品 | 成人免费视频免费观看 | 毛片网站在线 | 伊人国产在线观看 | 国产99黄| 天天色天天爱天天射综合 | 国产精品高清免费在线观看 | 夜夜操天天干 | 亚洲国产日韩一区 | 日韩午夜小视频 | 天天操夜夜拍 | 涩涩网站在线 | 在线观看一 | 日韩精品一区二区在线观看 | 欧美精品久久久久久久免费 | 久久精品久久久精品美女 | 碰超在线97人人 | 日韩精选在线观看 | 婷婷激情五月综合 | 超碰97免费观看 | 日韩毛片久久久 | 亚洲国产精品女人久久久 | 欧美性大战久久久久 | 制服丝袜一区二区 | 久久久黄视频 | 美女视频免费精品 | 国产资源av| 成年人av在线播放 | 国产精品久久久久国产精品日日 | 日韩一区二区三区免费视频 | 美女免费黄视频网站 | 九九色综合 | 最新久久免费视频 | 波多野结衣在线视频免费观看 | 麻豆 free xxxx movies hd | 色综合久| 国产一级电影 | 天天做夜夜做 | 久久理论影院 | 免费成人看片 | 久久伦理| 香蕉视频一级 | 丁香久久综合 | 日本韩国精品一区二区在线观看 | 狠狠久久综合 | av一本久道久久波多野结衣 | 91精品一区二区三区蜜桃 | 久久系列| 99视频精品视频高清免费 | 国产精品成人品 | 国产亚州精品视频 | 国产97av| 日韩午夜电影院 | 欧美性色黄大片在线观看 | 国产精品久久久久久久久久99 | 波多野结衣在线观看一区二区三区 | 人人射人人插 | 亚洲天堂网在线观看视频 | 亚洲欧美在线观看视频 | 国产成人精品亚洲日本在线观看 | 亚洲91视频 | 国产一区二区三区免费观看视频 | 91你懂的 | 91九色蝌蚪视频在线 | 91视频在线免费观看 | 在线视频a| 91av视频在线播放 | 狠狠干中文字幕 | 日韩免费久久 | 中文有码在线视频 | 欧美精品一区二区在线观看 | 日韩欧美中文 | 天天操天天射天天爱 | 久久久www成人免费毛片 | 中文字幕精品www乱入免费视频 | 人人网av | 久久99日韩| 精品一区二区电影 | 国产91aaa| 国产日韩精品视频 | 久久免费99精品久久久久久 | 在线中文日韩 | 免费观看全黄做爰大片国产 | 91亚洲精品视频 | 日韩av一卡二卡三卡 | 人人爽人人| 少妇bbw搡bbbb搡bbbb | 国产丝袜在线 | 国产在线观看a | 三上悠亚一区二区在线观看 | 天天操天天曰 | 久久伊人国产精品 | 国产精品久久久久久久久婷婷 | 日韩视频一区二区在线 | 亚洲精品成人av在线 | 亚洲理论在线 | 日韩av成人 | 亚洲人在线7777777精品 | 久久久99国产精品免费 | 日韩理论片在线 | 九九精品久久 | 狠狠色丁香久久综合网 | 天天爽天天做 | 成人免费在线播放 | 97在线视频网站 | 在线视频国产区 | 一级黄色毛片 | 欧美视屏一区二区 | 成人久久久久久久久久 | 免费99精品国产自在在线 | 亚洲精品字幕在线 | 亚洲综合丁香 | 成人av高清在线观看 | 永久免费毛片 | 丁香六月在线 | 久久久久久久久久久久久9999 | 黄色视屏av| 日日干夜夜爱 | 午夜精品av | 亚洲精品免费在线视频 | 中文成人字幕 | 久草在线免费看视频 | 视频一区视频二区在线观看 | 欧美日韩激情视频8区 | 92中文资源在线 | 成人黄色影片在线 | 中文字幕免费久久 | 成人黄大片视频在线观看 | 色综合婷婷 | 人人精久 | 天天操 夜夜操 | 亚洲综合视频在线观看 | 人人爽人人插 | 久久狠狠婷婷 | 天天干,天天射,天天操,天天摸 | 亚洲国产美女久久久久 | 人人躁| 天天干,天天操,天天射 | 免费观看全黄做爰大片国产 | 欧美ⅹxxxxxx | 91视频91色| 精品国内自产拍在线观看视频 | 网站你懂的 | 日本精品久久久久影院 | 超碰97免费 | 国产99自拍| 精品女同一区二区三区在线观看 | 久久综合亚洲鲁鲁五月久久 | 亚洲麻豆精品 | 免费在线观看一区二区三区 | 96视频在线| 精品国产a| 色亚洲网 | 亚洲女在线 | 91精品欧美一区二区三区 | 国产精品一区二区久久精品爱涩 | 人人澡人| 人人爱夜夜操 | 成人免费网站视频 | 亚洲va欧美va人人爽春色影视 | 深夜福利视频一区二区 | 亚洲欧美视频在线播放 | 婷婷九月激情 | 在线观看国产91 | 精品国产一区二区三区蜜臀 | 国产生活一级片 | 日韩欧美在线视频一区二区 | 国产97色在线 | 中文字幕免费一区 | 国产精品99久久久久久大便 | 亚洲 综合 专区 | 国产一级片免费播放 | 97视频免费在线观看 | 午夜丰满寂寞少妇精品 | 成人看片 | 欧美精品久久久久性色 | 日韩午夜一级片 | 99国产在线 | 成年人免费在线观看网站 | 国产伦精品一区二区三区免费 | 天天天天色综合 | 天天射射天天 | 中文字幕国产精品 | 日韩三级一区 | 国产亚洲久一区二区 | 国产精品不卡在线播放 | 欧美精品中文在线免费观看 | 天天操天天插 | 91av在线免费| 免费看污在线观看 | 毛片1000部免费看 | 日韩网站在线免费观看 | 色av色av色av | 视色网站 | 激情视频网页 | 在线小视频你懂的 | 高清av免费观看 | 欧美日韩国产一区二区三区在线观看 | 日韩精品免费在线视频 | 成人亚洲免费 | 国产精品a久久 | 国产色在线视频 | 国产美女精品久久久 | 99久久久久久国产精品 | 久久精品在线免费观看 | 精品一区二三区 | 免费成人av电影 | 99精品久久99久久久久 | 日韩欧美精品在线 | 久久调教视频 | 婷婷伊人五月天 | 四虎8848免费高清在线观看 | 国产一区自拍视频 | 国产97在线看 | 狠狠操夜夜操 | 国产一区在线精品 | 97人人模人人爽人人喊网 | avlulu久久精品 | 二区精品视频 | 免费日韩 精品中文字幕视频在线 | 日韩一区二区三区视频在线 | 免费看一级特黄a大片 | 最近日本韩国中文字幕 | 天堂在线一区 | 欧美成人影音 | 国产精彩视频一区 | 久久综合色一综合色88 | 久久精品这里都是精品 | 日韩一级精品 | 97av超碰| 午夜精品视频免费在线观看 | www亚洲一区 | 久久视频免费观看 | 久久精品福利 | 久久综合日 | 日韩免费一区 | 2018好看的中文在线观看 | 国产成人精品久久二区二区 | 91高清免费 | 精品一区二区免费在线观看 | www在线免费观看 | 亚洲国产视频在线 | 国产精品粉嫩 | 国产福利91精品一区 | 99在线视频精品 | 在线观看免费日韩 | 久久观看最新视频 | 久久女同性恋中文字幕 | av福利网址导航大全 | 亚洲乱码久久久 | 国产黄色视 | 国产黄色网 | 久久免费视频2 | 国产精品毛片一区二区 | 国产亚洲视频在线 | 一级片免费观看视频 | 亚洲人人网 | 99久久婷婷国产综合精品 | 丁香视频在线观看 | 三级黄色网址 | 人人玩人人添人人澡超碰 | 久久精品国产免费看久久精品 | 天天插日日插 | 日韩欧美在线免费观看 | 免费观看mv大片高清 | 在线成人中文字幕 | 成人在线视频网 | 久久久999精品视频 国产美女免费观看 | 99视频久久 | 久久综合综合久久综合 | 亚洲另类在线视频 | 亚洲精品在线观看的 | 久久av观看| 99视频+国产日韩欧美 | 丁五月婷婷 | 91成人网页版 | 黄网站a| 精品国产一区二区三区四区在线观看 | 在线免费视频 你懂得 | 国产精品久久久久久久av电影 | 色橹橹欧美在线观看视频高清 | 99视频在线免费 | 色搞搞 | 国产一级二级三级视频 | 免费看的国产视频网站 | 91丨九色丨蝌蚪丨对白 | 五月色丁香 | 蜜臀久久99精品久久久酒店新书 | 日日夜夜亚洲 | 很污的网站 | 欧美人交a欧美精品 | 天天综合网国产 | 精品极品在线 | 亚洲黄色av网址 | 欧美91av| 免费看搞黄视频网站 | 日韩一二区在线观看 | 99视频精品免费视频 | 国产在线观看免 | 韩国精品在线观看 | 韩国av一区二区三区在线观看 | 国产第一页在线播放 | 免费观看v片在线观看 | 欧美九九九 | 国产黄视频在线观看 | 91完整版观看 | 国产免费一区二区三区网站免费 | 国产精品av免费 | 欧美另类69 | 国产在线中文字幕 | 国产一级二级三级视频 | 91免费观看国产 | 免费视频18 | 99久久夜色精品国产亚洲 | 免费看日韩片 | 亚洲精品美女久久久久网站 | 国内一级片在线观看 | 色亚洲网 | 色欧美视频 | 国产精品自在欧美一区 | 91自拍91| 免费看的黄色 | 成人av在线影视 | 日韩视频中文字幕在线观看 | 欧美日韩在线免费观看视频 | 国产69精品久久久久99 | 五月网婷婷 | 亚洲精品av中文字幕在线在线 | 国产综合福利在线 | 久久久久久国产精品免费 | www.色的| 美腿丝袜一区二区三区 | 色妞色视频一区二区三区四区 | 久久综合久色欧美综合狠狠 | 久久久精品国产一区二区三区 | 97视频在线免费观看 | 一区二区三区动漫 | 国产精品高清免费在线观看 | 日韩一级电影在线 | 婷婷丁香狠狠爱 | 国色天香在线 | 丁香激情综合久久伊人久久 | 男女视频久久久 | 午夜视频99 | 中文字幕在线视频一区 | 人人搞人人爽 | 亚洲精品在线二区 | 一本之道乱码区 | 国产在线观看一 | 在线一二三区 | 国产一区电影在线观看 | 国产一级片毛片 | 黄色一级大片在线免费看国产一 | 国产青春久久久国产毛片 | 久久的色| 精品999国产| 国内精品二区 | 亚洲成人午夜在线 | 久草在线中文视频 | 国产99久久99热这里精品5 | 国产a级免费 | 亚洲精品一区二区三区在线观看 | 日韩精品一区二区三区第95 | 欧美日韩亚洲一 | 人人爱人人爽 | 久久这里只有精品视频首页 | 免费看的黄色的网站 | 久九视频 | 欧美日韩一区二区三区在线观看视频 | 蜜桃av综合网 | 蜜臀av夜夜澡人人爽人人 | 国产精品久久久久久久av大片 | 久草视频首页 | 午夜精品久久久久久99热明星 | 综合网在线视频 | 久久影院精品 | 久久久国产精品成人免费 | 日韩专区av | 在线观看视频色 | 一二三久久久 | 欧美九九九| 亚洲精品久久久久中文字幕m男 | 玖玖精品视频 | 伊人国产在线播放 | 青草视频在线 | 日本黄色免费在线观看 | 蜜桃视频在线观看一区 | 欧美精品三级 | 天天干天天在线 | 久久综合国产伦精品免费 | 久久免费视频一区 | 国产日韩欧美在线观看 | 综合网中文字幕 | 1000部18岁以下禁看视频 | 一区二区三区不卡在线 | 欧美a√大片 | 久久久国产一区二区三区 | 亚洲精品一区二区三区在线观看 | 国产精品久久久久三级 | 亚洲三级视频 | 91在线91拍拍在线91 | 国产xvideos免费视频播放 | 久久免费视频这里只有精品 | www久久| 玖玖爱免费视频 | 欧美日韩有码 | 国产欧美精品一区二区三区四区 | 性色av一区二区三区在线观看 | 久久综合婷婷综合 | 婷婷丁香六月天 | 国产精品视频999 | 免费成人黄色av | 日韩影片在线观看 | 久久精品国产99国产 | 中文在线a√在线 | 国产精品日韩高清 | 日韩精品视频久久 | 国产色爽 | 91精品网站 | 欧美成人视| 高清日韩一区二区 | www.操.com| free,性欧美| 国产免费中文字幕 | www.亚洲激情.com | 91视频久久久久 | 九九精品毛片 | 97碰碰视频| 色婷婷在线视频 | 国产在线成人 | 99久久久久国产精品免费 | 亚洲视屏一区 | 亚洲电影一区二区 | 中文字幕亚洲综合久久五月天色无吗'' | 久草在线视频网 | 久操免费视频 | 成年美女黄网站色大片免费看 | 99精品免费久久久久久久久日本 | 国产在线播放一区二区 | 国产视频久久久 | 91精品国产91久久久久福利 | 久久久精品午夜 | 欧美日韩在线观看视频 | 天天操天天操天天爽 | 日韩精品最新在线观看 | 在线视频观看国产 | a久久久久 | 一级黄色片在线免费观看 | 一级精品视频在线观看宜春院 | 国产青草视频在线观看 | 在线观看色网站 | 91成人区 | 蜜桃麻豆www久久囤产精品 | 麻豆免费视频网站 | www夜夜操 | 欧美精品中文在线免费观看 | 国产福利久久 | 91麻豆精品国产91久久久使用方法 | av电影在线不卡 | 亚洲伊人网在线观看 | 亚洲免费av在线播放 | 99国内精品 | 欧美夫妻性生活电影 | 色综合久久久久综合 | 色婷婷精品大在线视频 | 美女黄频在线观看 | 五月婷香蕉久色在线看 | 成年人av在线播放 | 91免费版在线观看 | 欧美日韩一区二区免费在线观看 | 日韩理论在线视频 | 国内毛片毛片 | 欧美激情片在线观看 | 久久视频6 | 久久亚洲人 | 日日夜av| 国产在线观看一区 | www.色就是色 | 丁香在线 | 欧美a在线看 | 六月色丁 | 久久久久久久影院 | 涩五月婷婷 | 91日韩在线 | 色播六月天 | 一级黄色片在线免费观看 | 日韩精品在线视频免费观看 | 久久综合久久综合这里只有精品 | 91在线精品播放 | 成人a视频在线观看 | 香蕉视频免费在线播放 | 久久久电影网站 | 日韩在线视频不卡 | 日日添夜夜添 | 免费69视频| 黄网站色| 91亚洲精品久久久久图片蜜桃 | 国产视频一区二区在线播放 | 欧美日韩另类视频 | 亚洲一级电影 | 中文字幕丝袜美腿 | 亚洲日本国产精品 | 天天综合网在线 | 视频一区二区视频 | 久久伊人精品一区二区三区 | 午夜精品一区二区三区免费视频 | 99久久婷婷 | 免费观看一区二区三区视频 | 成人av免费| 人人添人人 | 国产精品美女视频 | 久久综合色播五月 | www.久久久.com | 国产视频资源 | 看黄色.com | 欧美一级免费 | 亚洲天堂视频在线 | 日日夜夜草 | 欧美做受69 | 国内精品久久久久久 | 国产福利专区 | 狠狠躁日日躁狂躁夜夜躁 | 久热精品国产 | 一区二区亚洲精品 | 丁香六月婷 | 特级西西444www大胆高清无视频 | 99午夜| 91免费在线播放 | 丰满少妇一级 | 超碰人人草人人 | 午夜视频在线网站 | 亚洲精品播放 | 在线播放第一页 | 蜜臀aⅴ国产精品久久久国产 | 国产伦精品一区二区三区四区视频 | 久久免费高清 | 人人草人人做 | 中文字幕文字幕一区二区 | 福利视频 | 国产精品色婷婷 | 中文字幕视频播放 | 不卡国产在线 | 国产福利精品一区二区 | 伊人导航 | 91麻豆传媒 | 高清中文字幕av | 久久草在线免费 | 久久免费大片 | 少妇高潮流白浆在线观看 | 91九色蝌蚪视频在线 | 国产精品一区二区三区久久 | 免费国产在线精品 | 国产不卡在线播放 | 99久在线精品99re8热视频 | 午夜精品三区 | 黄色在线免费观看网址 | 国产高清一区二区 | 免费在线色电影 | 国内精品久久久久久久久 | 黄色一级在线视频 | 九九日九九操 | 中文字幕在线观看完整版电影 | 爱色av.com | 久久精品中文 | av大片免费在线观看 | 天天做日日做天天爽视频免费 | 日韩在线观看你懂的 | 九九热视频在线 | 欧美激情一区不卡 | 亚洲精品在线国产 | 日韩另类在线 | 国产99一区视频免费 | 五月天伊人网 | 国产成人久久av977小说 | 色综合www| 国产精品一区二区av麻豆 | 国产在线精品区 | 视频一区二区国产 | 激情欧美一区二区免费视频 | 国产精品地址 | 国产.精品.日韩.另类.中文.在线.播放 | 久久国产精品久久精品国产演员表 | 麻豆综合网 | 99久久99久久综合 | 久久久久久国产一区二区三区 | 黄色a视频| av免费福利 | 成人免费观看在线视频 | 四虎免费在线观看视频 | 久久久久综合精品福利啪啪 | 免费男女羞羞的视频网站中文字幕 | 中文字幕精品一区久久久久 | 91桃花视频| 国产一区视频在线 | 一区二区三区免费在线观看视频 | 久草a在线 | 五月婷婷欧美 | 天天曰夜夜爽 | 欧美污污网站 | 97碰碰碰 | 这里只有精品视频在线 | 久久只有精品 | 色网站视频 | 成人一区二区三区在线 | 欧美亚洲免费在线一区 | 不卡av在线播放 | www.人人草 | 成人福利在线观看 | 婷婷在线播放 | 中文字幕第一页在线 | 一区二区三区精品在线视频 | 在线看岛国av | 91香蕉视频好色先生 | 91丨九色丨勾搭 | 韩国av在线播放 | 91视频这里只有精品 | 在线亚洲激情 | 欧美最猛性xxxx | 丁香六月婷婷综合 | 国产高清在线永久 | 91在线国产观看 | 91精品国产综合久久婷婷香蕉 | 黄av免费| 亚洲在线观看av | 亚洲视频 中文字幕 | 成年人免费av网站 | 成人h电影在线观看 | 91精品一区二区三区蜜桃 | 免费看污片 | 国产成人亚洲在线观看 | 五月婷婷综合久久 | 久草精品电影 | 99精品欧美一区二区三区黑人哦 | 久久撸在线视频 | 国产一区免费 | 人人爽人人做 | 日韩黄色在线电影 | 午夜精品麻豆 | 精品爱爱 | 亚洲第一中文字幕 | 成人小视频在线播放 | 狠狠干我 | 日本视频高清 | 国产精品黄色在线观看 | 亚洲最大av网 | 成年人电影免费在线观看 | 精品字幕| 免费的黄色的网站 | 欧美一级激情 | 93久久精品日日躁夜夜躁欧美 | 麻豆视频免费在线观看 | 欧美亚洲国产一卡 | 国产免费三级在线观看 | 在线免费视频a | 99热这里只有精品国产首页 | 国产69久久 | 国产在线精品一区二区三区 | 国产在线va | 欧洲色综合 | 国产精品第 | 最新日韩在线观看视频 | 96精品在线 | 日本精品久久久久中文字幕 | 99在线热播精品免费99热 | 亚洲一区二区黄色 | 99精品免费久久久久久久久 | 天天拍天天色 | 亚洲精品午夜久久久久久久 | 91爱看片| 亚洲区另类春色综合小说 | 精品国产免费人成在线观看 | 在线天堂v | 99久久精品国产毛片 | 爱爱av网 | 久久99国产精品久久99 | 91精品国产91久久久久久三级 | 中文字幕日韩一区二区三区不卡 | 国产精品一区二区av | 国产日韩av在线 | 久久精品老司机 | 国产拍在线 | 1024手机在线看 | 国产综合婷婷 | 国产一区欧美一区 | 中文字幕中文字幕在线中文字幕三区 | 日韩欧美综合视频 | 欧美亚洲精品一区 |