说明:
本文将帮助你理解SQL Server 2008表值参数,这里已经用了ASP.NET MVC Framework 3.0,但你可以用ASP.NET MVC的其它框架。
背景:
在面向对象程序设计的开发环境中,很多情况下,我们需要存储一整列对象到数据库中,在这些情况中,程序员采用以下两个选项之一:
用自定义分隔符来序列化对象阵列及其参数并在数据库端将它们并行化,执行所有数据库操作。但这使得计算变得相当复杂且费时,除了整列对象被当做varchar参数传递。
使整列对象成环并通过单独创建连接在每个阵列元素执行数据库操作。它在编程上不那么复杂但就我们需要在每个迭代上创建连接而言,依然不是一个可行的选项。
Microsoft SQL Server 2008能通过引入表值参数使得用户可以创建能轻易在存储程序中使用的自定义类型table的参数,来解决上述两个问题。
使用代码:
表值参数可以用如下语法来创建:
create type TVPType astable(Name nvarchar(500),Salary decimal(18,2),Age int,EndHeader bit);
在上述代码片段中,我们要注意创建自定义参数的类型和名称。在本例中,是表参数结构跟随表。一旦你执行代码,就可以在其中找到你的自定义参数。
现在我们需要创建程序来插入从应用中接收到的数据。我们将使用如下存储程序:
createproc AddDetails@tvp TVPType readonlyasbegininsertinto TVPTable(Name, Age, Salary) select t.Name,t.Age,t.Salary from@tvp t;end
由此现在我们已经完成了数据库方面,将转向应用方面。打开一个新的MVC项目或一个你想要使用的项目。我已经使用了类型化数据集替代实体框架,因为实体框架不支持能够用于表值参数的结构化类型参数。
如下即为应用的截图(在用表值参数插入记录到数据库的前后)。
插入记录前的页面显示:
现在当我们插入记录时,我已允许用户通过使用如下JavaScript代码插入任意量的记录:
function addRow() {var table = document.getElementById('recordTable').lastChild;if (table) {var id = Number(table.children[table.children.length-1].id);if (!isNaN(id)) { id+=1;var child = document.createElement('tr'); child.id = id;var html = '<input type="text" id="name_' + id + '" maxlength="50"/>'; html += '<input type="text" id="age_' + id + '"/>'; html += '<input type="text" id="salary_' + id + '"/>'; child.innerHTML = html; table.appendChild(child); } }}
用户可以用“Add more”按钮添加新行,最后用“Submit”按钮提交。
我们可以通过生成一个请求,用JSON对象传送所有数据到控制器。如下即是完成上述任务的JavaScript代码:
function submitRecords() {var table = document.getElementById('recordTable').lastChild;if (table) { var childArr = table.children;if (childArr.length > 0) {var jsonArr={tvp:[]};var nameObj, ageObj, salaryObj, id;var counter = 0;for (var i = 1; i < childArr.length; i++) { id = childArr[i].id; nameObj = document.getElementById('name_' + id); ageObj = document.getElementById('age_' + id); salaryObj = document.getElementById('salary_' + id);if (nameObj != null && nameObj.value.trim() != '' && ageObj != null && ageObj.value.trim() != '' && salaryObj != null && salaryObj.value.trim() != '') { jsonArr.tvp.push({"name":nameObj.value.trim(),"age":ageObj.value.trim(),"salary":salaryObj.value.trim() }); } }if (jsonArr.tvp.length > 0) { $.ajax({ url: "../TVP/SubmitRecord", data:{"data":JSON.stringify(jsonArr)}, type: "POST"}); } elsealert("Add data please"); } }}
在控制器一方,我们已经创建了一个函数SubmitRecord来接收我们的AJAX请求并将数据从AJAX请求中传递到相应的模型中。
[HttpPost]public ActionResult SubmitRecord(string data){ TVPModel.StoreValues(data);return View();}
在上述代码中,HttpPost属性指定了调用函数(接收当PSOT请求时)。我们已经用NewtonSoftJson库来在模型类别上(解析JSON数据并将其存储到DataTable)解析JSON对象。
publicstaticvoid StoreValues(string data){ JToken token = JObject.Parse(data);var tvp=token.SelectToken("tvp"); DataTable recordTable = Params.GetDetailsTable();foreach (var value in tvp) { DataRow row = recordTable.NewRow(); row["Name"] = value.SelectToken("name"); row["Age"] = value.SelectToken("age"); row["Salary"] = value.SelectToken("salary"); ; row["EndHeader"] = true; recordTable.Rows.Add(row); } TVPBL bl = new TVPBL(); bl.InsertTVP(recordTable);}
创建的DataTable被作为参数传送到数据库程序。该DataTable应该和数据库端的所述类型有着同样的结构。我们已经创建了一个BL类,负责为我们的类型化数据集创建一个表适配器并调用指定的程序。
publicvoid InsertTVP(DataTable tvpTable){ TVPTableTableAdapter adapter = GetTvpTableAdapter(); adapter.AddDetails(tvpTable);}
在完成上述程序后,我们的数据被存储在数据库中。现在当浏览主页显示“No details to show”消息时,它将不再可见。而主页将显示如下:
需要注意的点:
实体框架目前不支持表值参数。
表值参数不能被编辑但可以被删除和重建,仅当你的数据库中任意存储程序没有引用该表值参数时。
表值参数在只读模式中使用。
表值参数不能被用于数据库中用户定义函数。
DataTable的表值参数和结构应该匹配。比如,列应该被定义在同一个位置。
点击下载源代码