我正在努力完成一项看似简单的任务,该任务已经变成了几个小时的冒险:从@@Identity
获取TableAdapter.Insert()
。
这是我的代码:
protected void submitBtn_Click(object sender, EventArgs e)
{
AssetsDataSetTableAdapters.SitesTableAdapter sta = new AssetsDataSetTableAdapters.SitesTableAdapter();
int insertedID = sta.Insert(siteTxt.Text,descTxt.Text);
AssetsDataSetTableAdapters.NotesTableAdapter nta = new AssetsDataSetTableAdapters.NotesTableAdapter();
nta.Insert(notesTxt.Text, insertedID, null,null,null,null,null,null);
Response.Redirect("~/Default.aspx");
}
一个 answer 表示我可能需要做的就是更改ExecuteMode
。我试过了。这使GetData()
退出工作(因为我现在返回一个标量而不是rowdata)(我需要保留GetData())。它也没有解决这个问题,因为insertedID变量仍然设置为1。
我尝试在TableAdapter
中创建第二个TypedDataSet.XSD
并将该适配器的属性设置为“标量”,但它仍然失败,变量值为1.
生成的插入命令是
INSERT INTO [dbo].[Sites] ([Name], [Description]) VALUES (@Name, @Description);
SELECT Id, Name, Description FROM Sites WHERE (Id = SCOPE_IDENTITY())
并且“刷新数据表”(在Insert和Update语句之后添加select语句以检索Identity)也已设置。
环境
SQL Server 2008 R2,Visual Studio 2010,.NET 4,Windows XP,所有本地相同的计算机。
造成这种情况的原因是什么?
修改/更新
我想澄清我在Visual Studio中使用自动生成的代码。我不知道生成代码的“工具”是什么,但如果双击* .XSD文件,它会显示SQL表模式的UI和关联的TableAdapter。我想继续使用自动生成的代码,并以某种方式启用获取身份。我不想用存储过程手写这一切。
答案 0 :(得分:8)
真正的答案:
从tableadapter插入函数中获取标识
我经常对此问题提出疑问,而且从未找到过 把它写下来的时间。
嗯,问题是如下:你有一个主键为int的表 类型定义为Identity,插入后需要知道PK值 新插行。完成此操作的步骤如下:
使用向导在中添加新的插入查询(让我们称之为InsertQuery) 查询体只是在底部添加SELECT SCOPE_IDENTITY()之后 保存此查询,更改此查询的ExecuteMode属性 代码中的NonQuery to Scalar写下面的内容(ta是TableAdapter 实例):
int id; try { id = Convert.toInt32(ta.InsertQuery(firstName, lastName, description)); } catch (SQLException ex) { //... } finally { //... }
用这个赚钱! :)由DraškoSarić于2009年3月12日发表。
自: http://quickdeveloperstips.blogspot.nl/2009/03/get-identity-from-tableadapter-insert.html
备注:强>
可以通过生成的插入查询的属性将 ExecutMode 设置为 Scalar 。 (按F4)。
在我的版本(Visual Studio 2010 SP1)中,select语句是自动生成的。
答案 1 :(得分:4)
这是我的SQL代码。
CREATE PROCEDURE [dbo].[Branch_Insert]
(
@UserId uniqueidentifier,
@OrganisationId int,
@InsertedID int OUTPUT
)
AS
SET NOCOUNT OFF;
INSERT INTO [Branch] ([UserId], [OrganisationId])
VALUES (@UserId, @OrganisationId);
SELECT Id, UserId, OrganisationId FROM Branch WHERE (Id = SCOPE_IDENTITY())
SELECT @InsertedID = SCOPE_IDENTITY()
然后当我创建表适配器时 - 我可以立即看到@InsertedID参数。
然后从代码中,我所做的就是:
int? insertedId = 0;
branchTA.Insert(userId, orgId, ref insertedId);
我不是100%使用ref是最好的选择,但这对我有用。
祝你好运。答案 2 :(得分:1)
所有信息都在这里,但我没有找到任何单一的答案,所以这是我使用的完整步骤。
添加插入查询,并向其添加SELECT SCOPE_IDENTITY()
,如下所示:
INSERT INTO foo(bar) VALUES(@bar);
SELECT SCOPE_IDENTITY()
确保添加;到VS为你创建的INSERT语句的末尾。
完成添加查询向导后,请确保在设计视图中选择了查询,然后从属性窗格中将执行模式更改为Scalar
。
确保在从代码中调用查询时使用Convert.ToInt32(),如下所示:
id = Convert.ToInt32( dataTableAdapter.myInsertQuery("bar") )
如果没有Convert.ToInt32,您将不会遇到编译器错误,但是您将得到错误的返回值。
此外,每次修改查询时,都必须将执行模式重置为Scalar
,因为VS每次都会将其更改回Non Query
。
答案 3 :(得分:1)
这是你如何做到的(在可视化设计器中)
复制并粘贴您的SQL,它可以是多行的,只需确保“查询设计器”无法打开,因为它无法解释多个命令 - 我的示例显示了一个示例“merge”语句集(请注意,新的SERVERS具有Merge命令)。
UPDATE YOURTABLE
SET YourTable_Column1 = @YourTable_Column1, YourTable_Column2 = @YourTableColumn2
WHERE (YourTable_ID = @YourTable_ID)
IF @@ROWCOUNT=0
INSERT INTO YOURTABLE ([YourTable_Column1], [YourTable_Column2])
VALUES (@YourTable_Column1, @YourTable_Column2)
@YourTable_ID = SCOPE_IDENTITY()
从查询属性窗口/侧栏更改/添加@YourTable_ID参数。在参数集合编辑器中,ID参数需要具有InputOutput方向,以便在调用表适配器函数时更新该值。 (特别说明:确保您使InputOutput的任何列设计者没有将此列作为“只读”并且数据类型也匹配,否则更改数据表中的列或参数相应的信息)
这样可以节省为这种简单活动编写存储过程的需要。
很哇。您会注意到,此方法是一种快速执行数据层功能的方法,而不必闯入SQL过程并编写大量的过程。唯一的问题是,你必须做很多跳舞......答案 4 :(得分:0)
您需要设置插入以将标识作为输出值返回,然后将其作为适配器中的参数抓取。
这两个链接可以帮助您:
答案 5 :(得分:0)
您有两个选择:
我将使用以下SQL和ExecuteScalar。
INSERT INTO [dbo].[Sites] ([Name], [Description])
OUTPUT INSERTED.ID
VALUES (@Name, @Description);
答案 6 :(得分:-1)
一种方法是在insert命令后运行select查询。一个好方法是像这样包装原始命令:
public int WrapInsert(Parameters)
{
.....
int RowsAffected = this.Insert(..Parameters..);
if ( RowsAffected > 0)
{
try
{
SqlCommand cm = this.Connection.CreateCommand();
cm.CommandText = "SELECT @@IDENTITY";
identity = Convert.ToInt32(cm.ExecuteScalar());
}
finally
{
....
}
}
return RowsAffected;
}