必威注册电子书籍教程中心网文荟萃客户留言繁體中文
设为首页
加入收藏
联系必威注册
您当前的位置:92动力网 -> 教程中心 -> 编程经验 -> JAVA DotNet -> 教程内容 退出登录 用户管理
栏目导航
· Visual Basic· Delphi
· Visual C++· C++ Builder
· JAVA DotNet· 其他相关
热门教程
· 如何在Visual Basic...
· 使用Visual Basic操...
· 使用VB6.0设计Activ...
· VB动态调用外部函数...
· 建立一个程序员自己...
· 如何编写高质量的VB...
· [图文] 为更新到Visual Bas...
· 再谈在VB中调用VC++...
· 用VB语言编程实现JP...
· 用DTS实现SQL数据库...
相关教程
· Works 2000 的特殊字...
· 对.NET Framework "...
· .NET Framework 自动...
· 充分利用网上Java资...
· 充分利用网上Java资...
· 我们个人认为写java...
· work with ant(incl...
· Fireworks资格认证考...
· [图文] 用Axialis IconWork...
· [组图] 用Fireworks MX制作...

Working with MS Access Stored Procedures in VB.NET Montaque(转贴)
作者:佚名聽聽来源:本站整理聽聽发布时间:2005-12-29 18:02:30聽聽发布人:admin

减小字体 增大字体


Working with MS Access Stored Procedures in VB.NET. Part 1
by David Wasserman, MCP


Article source code: msaccess_sp.zip

Introduction

In the more recent releases of Microsoft Access, great effort has gone into making this product a full-featured relational database system. Stored procedures, a functionality usually associated with enterprise database systems such as SQL Server, can now be found in Access. Stored procedures in Access have been available since Access 2000 and are native to the Jet 4 Database Engine. If you're accustomed to using stored procedures in SQL Server, then you'll be right at home with how they're used in Access. However there are some limitations to keep in mind. I'll discuss those later on.

This article will be broken down into two parts. Part one will describe in detail how to create stored procedures in Access using ADO.NET and Visual Basic.NET. Part two will demonstrate how to utilize the stored procedures created in part one by assembling a data access tier that can be modelled and used in your own applications. The code in this article has been tested using Access 2002, although it should also work with Access 2000.

How do stored procedures work in Access?

Unlike other objects in Access, stored procedures have no interface and cannot be created or run through the Access User Interface. The way to get them into your database is to simply code them. I'll show how that's done in ADO.NET.

When a stored procedure is added to an Access Database, the Jet Engine reworks the stored procedure syntax into a query object. To an Access developer this may sound like unnecessary work to code a query. However, it does have its advantages. Consider an application that has to break out into different versions when maintaining both an Access Database and a SQL Server Database. Using stored procedures will make it easier to write the code for the database tier of the application as the program will change very little between the different versions.

Creating Stored Procedures

To demonstrate, I'll first show how to create the SQL statements to create stored procedures. At the end of the article I'll show the entire code needed to run these statements against the database. Using the Northwind database that comes with Access, four stored procedures will be created. Focusing on the Products table for all of them, let's start off with the easiest one; select all data of each row in the table. To create the stored procedure, execute the following SQL statement against the database:

"CREATE PROC procProductsList AS SELECT * FROM Products;"

The statement: "CREATE PROC procCustomerList" is the part that actually creates the stored procedure. The part following "AS" can be any valid SQL Statement.

Often in a stored procedure you'll want to pass a value to be used in the query. Consider that you may want to delete a record based on a particular ProductID. The following stored procedure shows how to do just that:

"CREATE PROC procProductsDeleteItem(inProductsID LONG)" & _
"AS DELETE FROM Products WHERE ProductsID = inProductsID;"

On the first line, notice the parenthesis right after the CREATE PROC declaration. There is a parameter defined as a Long value. This is where you add the variable to delete the record in question.

The next two statements show how to create an add and an update stored procedure for the Products table respectively. Note that not all fields are included for the sake of brevity:

"CREATE PROC procProductsAddItem(inProductName VARCHAR(40), " & _
"inSupplierID LONG, inCategoryID LONG) " & _
"AS INSERT INTO Products (ProductName, SupplierID, CategoryID) " & _
"Values (inProductName, inSupplierID, inCategoryID);"
"CREATE PROC procProductsUpdateItem(inProductID LONG, " & _
"聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽inProductName VARCHAR(40)) " & _
"AS UPDATE Products SET ProductName = inProductName " & _
"聽聽聽聽WHERE ProductID = inProductID;"

Notice that a comma separates each parameter when more than one is specified.

Limitations

There are some limitations you may encounter here, especially if you're used to the power of SQL Server.

  • Output parameters cannot be used.
  • Don't use the @ character. The @ character is often used in Transact SQL (SQL Server), where it represents a local variable. Access doesn't always convert this character and will sometimes leave it out. This can cause esoteric bugs which can lead to premature hair loss.
  • Temporary tables are not available in Access.
  • I suspect many of the options available in Transact SQL are not available in Access as it's not Transact SQL compatible.

Conclusion

Hopefully, this article has provided some guidance in a nearly undocumented area of Access and Jet not yet explored by most. For more information on how the ADO.NET code works in the CreateStoredProc subroutine, see Getting Started with ADO.NET by Gurneet Singh. The following is a complete listing of all code presented in this article:

<-- Generated using PrettyCode.Encoder at http://www.vbcity.com/encoder --><-- PrettyCode.Encoder Copyright (c) 2000 vbCity.com --><-- START http://www.vbcity.com/encoder -->
Importshttp://92power.net/files/Article/17/110/2005/SystemImportsSystem.DataImportsSystem.Data.OleDbModuleCreateSP聽聽聽聽SubMain()聽聽聽聽聽聽聽聽ProductsProcs()聽聽聽聽EndSub聽聽聽聽'聽Products聽Stored聽Procs聽to聽be聽added聽to聽the聽db.聽聽聽聽SubProductsProcs()聽聽聽聽聽聽聽聽DimsSQLAsString聽聽聽聽聽聽聽聽'聽procProductsList聽-聽Retrieves聽entire聽table聽聽聽聽聽聽聽聽sSQL="CREATE聽PROC聽procProductsList聽AS聽SELECT聽*聽FROM聽Products;"聽聽聽聽聽聽聽聽CreateStoredProc(sSQL)聽聽聽聽聽聽聽聽'聽procProductsDeleteItem聽-聽Returns聽the聽details聽(one聽record)聽from聽the聽聽聽聽聽聽聽聽聽'聽JobTitle聽table聽聽聽聽聽聽聽聽sSQL="CREATE聽PROC聽procProductsDeleteItem(@ProductID聽LONG)聽AS聽"_聽聽聽聽聽聽聽聽聽聽聽聽&"DELETE聽FROM聽Products聽WHERE聽ProductID聽=聽@ProductID;"聽聽聽聽聽聽聽聽CreateStoredProc(sSQL)聽聽聽聽聽聽聽聽'聽procProductsAddItem聽-聽Add聽one聽record聽to聽the聽JobTitle聽table聽聽聽聽聽聽聽聽sSQL="CREATE聽PROC聽procProductsAddItem(inProductName聽VARCHAR(40),聽"_聽聽聽聽聽聽聽聽聽聽聽聽&"inSupplierID聽LONG,聽inCategoryID聽LONG)聽AS聽INSERT聽INTO聽"_聽聽聽聽聽聽聽聽聽聽聽聽&"Products聽(ProductName,聽SupplierID,聽CategoryID)聽Values聽"_聽聽聽聽聽聽聽聽聽聽聽聽&"(inProductName,聽inSupplierID,聽聽聽CategoryID);"聽聽聽聽聽聽聽聽CreateStoredProc(sSQL)聽聽聽聽聽聽聽聽'聽procProductsUpdateItem聽-聽Update聽one聽record聽on聽the聽JobTitle聽table聽聽聽聽聽聽聽聽sSQL="CREATE聽PROC聽procProductsUpdateItem(inProductID聽LONG,聽"_聽聽聽聽聽聽聽聽聽聽聽聽&"inProductName聽VARCHAR(40))聽AS聽UPDATE聽Products聽SET聽"_聽聽聽聽聽聽聽聽聽聽聽聽&"ProductName聽=聽inProductName聽WHERE聽ProductID聽=聽inProductID;"聽聽聽聽聽聽聽聽CreateStoredProc(sSQL)聽聽聽聽EndSub聽聽聽聽'聽Execute聽the聽creation聽of聽Stored聽Procedures聽聽聽聽SubCreateStoredProc(ByValsSQLAsString)聽聽聽聽聽聽聽聽DimconAsOleDbConnection聽聽聽聽聽聽聽聽DimcmdAsOleDbCommand=NewOleDbCommand()聽聽聽聽聽聽聽聽DimdaAsOleDbDataAdapter聽聽聽聽聽聽聽聽'聽Change聽Data聽Source聽to聽the聽location聽of聽Northwind.mdb聽on聽your聽local聽聽聽聽聽聽聽聽聽'聽system.聽聽聽聽聽聽聽聽DimsConStrAsString="PROVIDER=Microsoft.Jet.OLEDB.4.0;Data聽"_聽聽聽聽聽聽聽聽聽聽聽聽&"Source=C:Program聽FilesMicrosoft聽"_聽聽聽聽聽聽聽聽聽聽聽聽&"OfficeOffice10SamplesNorthwind.mdb"聽聽聽聽聽聽聽聽con=NewOleDbConnection(sConStr)聽聽聽聽聽聽聽聽cmd.Connection=con聽聽聽聽聽聽聽聽cmd.CommandText=sSQL聽聽聽聽聽聽聽聽con.Open()聽聽聽聽聽聽聽聽cmd.ExecuteNonQuery()聽聽聽聽聽聽聽聽con.Close()聽聽聽聽EndSubEndModule
 Working with MS Access Stored Procedures in VB.NET. Part 2 
by
David Wasserman, MCP


Article source code: msaccess_sp2.zip

Introduction

Welcome to part two of Access Stored Procedures. Part one described in detail how to create stored procedures in Access using ADO.NET and Visual Basic.NET. Part two will demonstrate how to utilize the stored procedures created in part one by assembling a Database Tier that can be modelled and used in your own applications. This article will describe in detail one implementation of a Database Tier for Visual Basic.NET.

The main purpose of the Database Tier is to provide a gateway to the database via a class module. This class module would act as the glue between the database and the application. There are two main advantages to using a data tier to access your database. You will have the ability to modify your underlying database technology (moving from MS Access to SQL Server for instance) without affecting your application in a major way. You will also be placing a control layer between your application and the database allowing you to ensure that all data is properly "cleansed". The Database Tier in .NET applications would most likely consist of a class module keeping in line with proper object-oriented coding conventions. Earlier versions of Visual Basic would employ a Standard Module to do the job.

Database Tier - Code

It's now time to roll up our sleeves and get dirty with some code. The first thing after adding an empty class declaration file is to pull in the proper .NET Framework libraries listed below.

<-- Generated using PrettyCode.Encoder at http://www.vbcity.com/encoder --><-- PrettyCode.Encoder Copyright (c) 2000 vbCity.com --><-- START http://www.vbcity.com/encoder -->
ImportsSystemImportsSystem.DataImportsSystem.Data.OleDb
<-- END http://www.vbcity.com/encoder -->

The System Library is standard for most applications, and I make it a habit to include it in almost all my code modules. The System.Data library is necessary for almost all database access applications. The System.Data.OleDb is used specifically for OLEDB Database Providers to which Microsoft Access belongs to. If we were using SQL Server we'd include the custom SQL provider System.Data.SqlClient.

Then next line of code starts the definition of the Class:

<-- Generated using PrettyCode.Encoder at http://www.vbcity.com/encoder --><-- PrettyCode.Encoder Copyright (c) 2000 vbCity.com --><-- START http://www.vbcity.com/encoder -->
PublicClassDBTier
<-- END http://www.vbcity.com/encoder -->

Here we've named the Class DBTier and have given it a modifier of Public, thus making it very accessible from other code modules. After the class is defined all properties are declared:

<-- Generated using PrettyCode.Encoder at http://www.vbcity.com/encoder --><-- PrettyCode.Encoder Copyright (c) 2000 vbCity.com --><-- START http://www.vbcity.com/encoder -->
SharedconnectionStringAsString=_聽聽聽聽"PROVIDER=Microsoft.Jet.OLEDB.4.0;Data聽Source=C:Program聽"_聽聽聽聽&"FilesMicrosoft聽OfficeOffice10SamplesNorthwind.mdb"
<-- END http://www.vbcity.com/encoder -->

Only one property is declared here as a string variable, connectionString. This variable holds the connection string for the Northwind Access Database. Declaring the variable as Shared defines it as "Class Variable". A class variable is associated with the class, not each object instantiated from the class.

After the connection string declaration you'll find there are three subroutines and one function. The function returns a dataset with a listing of all products. It calls the stored procedure procProductsList, created in part one of this article.

Next you'll find the three subroutines. There is one for each stored procedure; add, update and deletion of products. They're all similarly structured; each with a command, connection and required parameter(s) declared. As a sample, let's dissect the ProductsDeleteItem subroutine. After understanding how this subroutine works the others should be easy to digest.

To start off the routine takes in one parameter, ProductID, which is an Integer representing the Product to be deleted.

<-- Generated using PrettyCode.Encoder at http://www.vbcity.com/encoder --><-- PrettyCode.Encoder Copyright (c) 2000 vbCity.com --><-- START http://www.vbcity.com/encoder -->
SubProductsDeleteItem(ByValProductIDAsInteger)
<-- END http://www.vbcity.com/encoder -->

Next, all variables are declared. One for the connection, command and a parameter to be passed into the stored procedure. This parameter is the ProductID to be deleted.

<-- Generated using PrettyCode.Encoder at http://www.vbcity.com/encoder --><-- PrettyCode.Encoder Copyright (c) 2000 vbCity.com --><-- START http://www.vbcity.com/encoder -->
DimconAsOleDbConnectionDimcmdAsOleDbCommand=NewOleDbCommand()DimparamProductIDAsNewOleDbParameter()
<-- END http://www.vbcity.com/encoder -->

Command and connection objects are initialized:

<-- Generated using PrettyCode.Encoder at http://www.vbcity.com/encoder --><-- PrettyCode.Encoder Copyright (c) 2000 vbCity.com --><-- START http://www.vbcity.com/encoder -->
con=NewOleDbConnection(connectionString)cmd.Connection=con
<-- END http://www.vbcity.com/encoder -->

The paramProductID parameter properties are configured. Then the parameter is added to the command object. In this case the parameter name in the stored procedure is inProductID, it's an integer and the value is set to the ProductID passed into this subroutine.

<-- Generated using PrettyCode.Encoder at http://www.vbcity.com/encoder --><-- PrettyCode.Encoder Copyright (c) 2000 vbCity.com --><-- START http://www.vbcity.com/encoder -->
WithparamProductID聽聽聽聽.ParameterName="inProductID"聽聽聽聽.OleDbType=OleDbType.Integer聽聽聽聽.Size=4聽聽聽聽.Value=ProductIDEndWithcmd.Parameters.Add(paramProductID)
<-- END http://www.vbcity.com/encoder -->

The last part actually calls the stored procedure.

<-- Generated using PrettyCode.Encoder at http://www.vbcity.com/encoder --><-- PrettyCode.Encoder Copyright (c) 2000 vbCity.com --><-- START http://www.vbcity.com/encoder -->
cmd.CommandText="EXECUTE聽procProductsDeleteItem"con.Open()cmd.ExecuteNonQuery()con.Close()
<-- END http://www.vbcity.com/encoder -->

Notice that the connection object only stays open long enough to carry out the stored procedure and then closes immediately. This reduces any possible contention.

While the DBTier class included in this article clearly describes how to access the stored procedures, it would need some enhancements to become quality production code since no error handling has been added. There may also be the need to further enhance performance here.

The downloaded source code associated with this article includes the DBTier.vb file along with some very basic forms to test the actual implementation of the class.

In conclusion, I hope you have gained at least two things from these articles. One being that stored procedures are alive and well in Microsoft Access, although not without their limitations. The second thing to walk away with here is understanding the need to break down an application's data access into separate classes, subroutines and functions. This makes maintenance and upgrades much easier to implement.

Entire DBTier.vb source code:

<-- Generated using PrettyCode.Encoder at http://www.vbcity.com/encoder --><-- PrettyCode.Encoder Copyright (c) 2000 vbCity.com --><-- START http://www.vbcity.com/encoder -->
Importshttp://92power.net/files/Article/17/110/2005/SystemImportsSystem.DataImportsSystem.Data.OleDb'聽Functions聽and聽subroutines聽for聽executing聽Stored聽Procedures聽in聽Access.PublicClassDBTier聽聽聽聽'聽Change聽Data聽Source聽to聽the聽location聽of聽Northwind.mdb聽on聽your聽local聽聽聽聽聽'聽system.聽聽聽聽SharedconnectionStringAsString=_聽聽聽聽聽聽聽聽"PROVIDER=Microsoft.Jet.OLEDB.4.0;Data聽Source=C:Program聽"_聽聽聽聽聽聽聽聽&"FilesMicrosoft聽OfficeOffice10SamplesNorthwind.mdb"聽聽聽聽'聽This聽function聽returns聽a聽dataset聽containing聽all聽records聽in聽聽聽聽'聽the聽Products聽Table.聽聽聽聽FunctionProductsList()聽AsDataSet聽聽聽聽聽聽聽聽DimconAsOleDbConnection聽聽聽聽聽聽聽聽DimdaAsOleDbDataAdapter聽聽聽聽聽聽聽聽DimdsAsDataSet聽聽聽聽聽聽聽聽DimsSQLAsString聽聽聽聽聽聽聽聽sSQL="EXECUTE聽procProductsList"聽聽聽聽聽聽聽聽con=NewOleDbConnection(connectionString)聽聽聽聽聽聽聽聽da=NewOleDbDataAdapter(sSQL,聽con)聽聽聽聽聽聽聽聽ds=NewDataSet()聽聽聽聽聽聽聽聽da.Fill(ds,聽"Products")聽聽聽聽聽聽聽聽Returnds聽聽聽聽EndFunction聽聽聽聽'聽This聽Function聽adds聽one聽record聽to聽the聽Products聽table.聽聽聽聽SubProductsAddItem(ByValProductNameAsString,聽_聽聽聽聽聽聽聽聽ByValSupplierIDAsInteger,聽ByValCategoryIDAsInteger)聽聽聽聽聽聽聽聽DimconAsOleDbConnection聽聽聽聽聽聽聽聽DimcmdAsOleDbCommand=NewOleDbCommand()聽聽聽聽聽聽聽聽DimparamProductNameAsNewOleDbParameter()聽聽聽聽聽聽聽聽DimparamSupplierIDAsNewOleDbParameter()聽聽聽聽聽聽聽聽DimparamCategoryIDAsNewOleDbParameter()聽聽聽聽聽聽聽聽con=NewOleDbConnection(connectionString)聽聽聽聽聽聽聽聽cmd.Connection=con聽聽聽聽聽聽聽聽WithparamProductName聽聽聽聽聽聽聽聽聽聽聽聽.ParameterName="inProductName"聽聽聽聽聽聽聽聽聽聽聽聽.OleDbType=OleDbType.VarChar聽聽聽聽聽聽聽聽聽聽聽聽.Size=40聽聽聽聽聽聽聽聽聽聽聽聽.Value=ProductName聽聽聽聽聽聽聽聽EndWith聽聽聽聽聽聽聽聽cmd.Parameters.Add(paramProductName)聽聽聽聽聽聽聽聽WithparamSupplierID聽聽聽聽聽聽聽聽聽聽聽聽.ParameterName="inSupplierID"聽聽聽聽聽聽聽聽聽聽聽聽.OleDbType=OleDbType.Integer聽聽聽聽聽聽聽聽聽聽聽聽.Size=4聽聽聽聽聽聽聽聽聽聽聽聽.Value=SupplierID聽聽聽聽聽聽聽聽EndWith聽聽聽聽聽聽聽聽cmd.Parameters.Add(paramSupplierID)聽聽聽聽聽聽聽聽WithparamCategoryID聽聽聽聽聽聽聽聽聽聽聽聽.ParameterName="inCategoryID"聽聽聽聽聽聽聽聽聽聽聽聽.OleDbType=OleDbType.Integer聽聽聽聽聽聽聽聽聽聽聽聽.Size=4聽聽聽聽聽聽聽聽聽聽聽聽.Value=CategoryID聽聽聽聽聽聽聽聽EndWith聽聽聽聽聽聽聽聽cmd.Parameters.Add(paramCategoryID)聽聽聽聽聽聽聽聽cmd.CommandText="EXECUTE聽procProductsAddItem"聽聽聽聽聽聽聽聽con.Open()聽聽聽聽聽聽聽聽cmd.ExecuteNonQuery()聽聽聽聽聽聽聽聽con.Close()聽聽聽聽EndSub聽聽聽聽'聽This聽function聽Updates聽a聽specific聽JobTitle聽Record聽with聽new聽data.聽聽聽聽SubProductsUpdateItem(ByValProductIDAsInteger,聽_聽聽聽聽聽聽聽聽ByValProductNameAsString)聽聽聽聽聽聽聽聽DimconAsOleDbConnection聽聽聽聽聽聽聽聽DimcmdAsOleDbCommand=NewOleDbCommand()聽聽聽聽聽聽聽聽DimparamProductNameAsNewOleDbParameter()聽聽聽聽聽聽聽聽DimparamProductIDAsNewOleDbParameter()聽聽聽聽聽聽聽聽con=NewOleDbConnection(connectionString)聽聽聽聽聽聽聽聽cmd.Connection=con聽聽聽聽聽聽聽聽WithparamProductID聽聽聽聽聽聽聽聽聽聽聽聽.ParameterName="inProductID"聽聽聽聽聽聽聽聽聽聽聽聽.OleDbType=OleDbType.Integer聽聽聽聽聽聽聽聽聽聽聽聽.Size=4聽聽聽聽聽聽聽聽聽聽聽聽.Value=ProductID聽聽聽聽聽聽聽聽EndWith聽聽聽聽聽聽聽聽cmd.Parameters.Add(paramProductID)聽聽聽聽聽聽聽聽WithparamProductName聽聽聽聽聽聽聽聽聽聽聽聽.ParameterName="inProductName"聽聽聽聽聽聽聽聽聽聽聽聽.OleDbType=OleDbType.VarChar聽聽聽聽聽聽聽聽聽聽聽聽.Size=40聽聽聽聽聽聽聽聽聽聽聽聽.Value=ProductName聽聽聽聽聽聽聽聽EndWith聽聽聽聽聽聽聽聽cmd.Parameters.Add(paramProductName)聽聽聽聽聽聽聽聽cmd.CommandText="EXECUTE聽procProductsUpdateItem"聽聽聽聽聽聽聽聽con.Open()聽聽聽聽聽聽聽聽cmd.ExecuteNonQuery()聽聽聽聽聽聽聽聽con.Close()聽聽聽聽EndSub聽聽聽聽'聽This聽function聽deletes聽one聽record聽from聽the聽Products聽table.聽聽聽聽SubProductsDeleteItem(ByValProductIDAsInteger)聽聽聽聽聽聽聽聽DimconAsOleDbConnection聽聽聽聽聽聽聽聽DimcmdAsOleDbCommand=NewOleDbCommand()聽聽聽聽聽聽聽聽DimparamProductIDAsNewOleDbParameter()聽聽聽聽聽聽聽聽con=NewOleDbConnection(connectionString)聽聽聽聽聽聽聽聽cmd.Connection=con聽聽聽聽聽聽聽聽WithparamProductID聽聽聽聽聽聽聽聽聽聽聽聽.ParameterName="inProductID"聽聽聽聽聽聽聽聽聽聽聽聽.OleDbType=OleDbType.Integer聽聽聽聽聽聽聽聽聽聽聽聽.Size=4聽聽聽聽聽聽聽聽聽聽聽聽.Value=ProductID聽聽聽聽聽聽聽聽EndWith聽聽聽聽聽聽聽聽cmd.Parameters.Add(paramProductID)聽聽聽聽聽聽聽聽cmd.CommandText="EXECUTE聽procProductsDeleteItem"聽聽聽聽聽聽聽聽con.Open()聽聽聽聽聽聽聽聽cmd.ExecuteNonQuery()聽聽聽聽聽聽聽聽con.Close()聽聽聽聽EndSubEndClass
<-- END http://www.vbcity.com/encoder -->
<-- END http://www.vbcity.com/encoder -->

[] [返回上一页] [打 印] [收 藏]
∷相关教程评论∷    (评论内容只代表网友观点,与本站立场无关!) [更多评论...]
关于本站 - 网站帮助 - 广告合作 - 下载声明 - 网站地图 - 管理登录
Copyright 2019 必威注册. All Rights Reserved .
浙ICP备05047688号