繁体   English   中英

使用LINQ将数据插入到使用序列作为主键生成器的表中

[英]Using LINQ to insert data into a table that uses a sequence as primary key generator

我有一个表,该表从一个序列(仅从0开始计数)生成其主键:

CREATE TABLE [dbo].[testTable](
    [id] [int] NOT NULL,
    [a] [int] NOT NULL,
 CONSTRAINT [PK_testTable] PRIMARY KEY CLUSTERED ([id] ASC))

ALTER TABLE [dbo].[tblTestTable] ADD  CONSTRAINT [DF_tblTestTable_id]  DEFAULT (NEXT VALUE FOR [seq_PK_tblTestTable]) FOR [id]

我已经使用Visual Studio的O / R设计器来创建表的映射文件。 id字段定义为:

[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_id", DbType="Int NOT NULL", IsPrimaryKey=true)]
public int id {…}

现在我正在尝试通过LINQ插入数据。

var testTableRecord = new testTable()
{
    a = 1,
};
db.Connection.Open();
db.testTables.InsertOnSubmit(testTableRecord);
db.SubmitChanges();
Console.WriteLine($"id: {testTableRecord.id}");

我遇到的问题是,LINQ似乎无法通过序列处理ID生成,因为插入时将id隐式设置为0。

  • 当我将id设置为CanBeNull ,插入将失败,因为它尝试将NULL插入非空字段。
  • 当我将id设置为IsDbGenerated ,插入可以工作,但是它需要一个IDENTITY字段,并尝试使用SELECT CONVERT(Int,SCOPE_IDENTITY()) AS [value]',N'@p0 int',@p0=1然后将对象中的id设置为null,因为SCOPE_IDENTITY()返回null
  • 我一直在考虑只使用IsDbGenerated ,销毁LINQ对象并向数据库查询id ,但是我没有什么可以搜索的。

不幸的是,不能将ID创建机制更改为IDENTITY。

我是否必须明确查询数据库以获取下一个序列值并手动设置ID?

通过LINQ处理这些插入物的最佳方法是什么?

PS:我需要ID,因为我必须插入更多使用ID作为FK的数据。

从原始sql角度看解决方案:

1。

INSERT INTO [dbo].[testTable] VALUES (NEXT VALUE FOR [dbo].[seq_PK_tblTestTable], 1)

据我所知,根本无法在LINQ to SQL中完成

2。

INSERT INTO [dbo].[testTable] (a) VALUES (1)

通过从testTable实体中排除id属性,可以在LINQ to SQL中实现这一点。

如果需要从表中检索ID,则可以创建单独的实体以进行插入和查询:

public class testTableInsert {
    [ColumnAttribute(...)]
    public int a
}

public class testTableResult {
    [ColumnAttribute(...)]
    public int id

    [ColumnAttribute(...)]
    public int a
}

3。

DECLARE @nextId INT;
SELECT @nextId = NEXT VALUE FOR [dbo].[seq_PK_tblTestTable];  
INSERT INTO [dbo].[testTable] VALUES (@nextId, 1)

如您所述,这可以通过在每次插入之前手动请求下一个ID来实现。 如果您采用这种方法,则可以在代码中采用多种方法来实现它,可以考虑使用存储过程或使用LINQ数据上下文手动执行sql来检索下一个序列值。

这是一个代码示例,演示如何使用部分方法扩展生成的DataContext。

public partial class MyDataContext : System.Data.Linq.DataContext
{
    partial void InsertTestTable(TestTable instance)
    {

        using (var cmd = Connection.CreateCommand()) 
        {
            cmd.CommandText = "SELECT NEXT VALUE FOR [dbo].[seq_PK_TestTable] as NextId";
            cmd.Transaction = Transaction;
            int nextId = (int) cmd.ExecuteScalar();
            instance.id = nextId;

            ExecuteDynamicInsert(instance);
        }         
    }
}

一旦实现了上述内容,您就可以安全地插入这样的实体,它们将生成正确的序列ID。

TestTable entity = new TestTable { a = 2 };
dataContext.TestTables.InsertOnSubmit(entity);
dataContext.SubmitChanges();

您唯一的希望是进行深刻的重构,并使用存储过程插入记录 可以将存储过程映射到数据上下文设计器中类的Insert方法。

使用表定义,存储的内容只不过是这样:

CREATE PROCEDURE InsertTestTable
(
    @id int OUTPUT,
    @a AS int
)
AS
BEGIN
    INSERT dbo.testTable (a) VALUES (@a);

    SET @id = (SELECT CONVERT(int, current_value) 
        FROM sys.sequences WHERE name = 'seq_PK_tblTestTable')
END

通过将其从Sql Object Explorer拖到设计器图面上,可以将其存储到上下文中,然后将其如下所示:

dbml设计器

下一步是单击testTable类,然后单击Insert方法的省略号按钮(通过将存储过程添加到上下文中来启用该按钮):

设置插入方法

并如下对其进行自定义:

设置插入方法对话框

就这样。 现在,LINQ-to-SQL将生成一个存储过程调用以插入一条记录,例如:

declare @p3 int
set @p3=8

declare @p5 int
set @p5=0
exec sp_executesql N'EXEC @RETURN_VALUE = [dbo].[InsertTestTable] @id = @p0 OUTPUT, 
    @a = @p1',N'@p0 int output,@p1 int,@RETURN_VALUE int output',
    @p0=@p3 output,@p1=123,@RETURN_VALUE=@p5 output
select @p3, @p5

当然,您可能不得不怀疑要挂多久才能使用LINQ-to-SQL。 实体框架核心具有开箱即用的序列支持。 以及更多。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM