【问题标题】:Performing a INSERT INTO ... SELECT with LINQ to SQL使用 LINQ to SQL 执行 INSERT INTO ... SELECT
【发布时间】:2011-01-22 19:21:02
【问题描述】:

我试图弄清楚是否可以使用 LINQ to SQL 执行“插入...选择”类型的命令。一些 LINQ to SQL 代码允许我向数据库发送一个 SQL 命令,该数据库将多行插入到给定的表中。

例如,如何让 LINQ to SQL 将以下 T-SQL 语句发送到 SQL Server 数据库?

INSERT INTO Table1 
SELECT Table2.column1 + 1 AS column1, Table2.column2 + 2 AS column2
WHERE Table2.column3 > 100

我当然可以通过使用DataContext.ExecuteCommand 函数来实现这一点,但这将立即执行,而无需利用DataContext.SubmitChanges 获得的自动事务处理。除了这个,我还有一系列更新,如果出现错误,我希望它们全部回滚。

有什么想法吗?

更新:这是实际代码:

        var bs_prep =
            from b in dc.T_EDR_FILEBODies
            join
            unpaid in dc.V_UNPAIDs
            on
                b.NUM_ADC.Substring(1, 9) equals unpaid.NOCONT
            join
            acordo in dc.T_ACORDOS_RECOM_APREs
            on
                Convert.ToInt32(b.NUM_ADC.Substring(1, 9)) equals acordo.ID_Contrato
            where
                b.ID_EDR == id_edr
                &&
                (
                    unpaid.NUM_INCUMPRIMENTOS <= max_unpaid_consec
                    &&
                    unpaid.TOTAL_NUM_INCUPRIMENTOS <= max_unpaid_nonconsec
                )
                ||
                (
                    acordo.Activo == true
                    &&
                    acordo.Data_Recomeco <= now
                )
            select new
                {
                    ID_EDR = id_edr_filt,
                    NUM_LINHA = b.NUM_LINHA,
                    CODREJ = b.CODREJ,
                    HDT = b.HDT,
                    IMPORT = b.IMPORT,
                    NIB_DEV = b.NIB_DEV,
                    NUM_ADC = b.NUM_ADC,
                    REF_DD_BC = b.REF_DD_BC,
                    REF_MOV = b.REF_MOV
                }
            ;


        dc.T_EDR_FILEBODies.InsertAllOnSubmit(
            bs_prep.Select(
                b => new T_EDR_FILEBODY{
                    CODREJ = b.CODREJ,
                    HDT = b.HDT,
                    ID_EDR = b.ID_EDR,
                    IMPORT = b.IMPORT,
                    NIB_DEV = b.NIB_DEV,
                    NUM_ADC = b.NUM_ADC,
                    NUM_LINHA = b.NUM_LINHA,
                    REF_DD_BC = b.REF_DD_BC,
                    REF_MOV = b.REF_MOV
                }
            )
        );

快速解释: T_EDR_FILEBODies 实体映射到一个数据库表,该表基本上存储了我们导入的一些文本文件的内容。一条记录对应文本文件中的一行。

我要做的是通过从一个文件中复制记录来创建文件内容的过滤版本,给它们一个新的文件 ID (ID_EDR=id_edr_filt),但过滤掉一些行。 LINQ to SQL 实体是到数据库表的直接映射。到目前为止,我没有向我的数据上下文添加任何代码。它们确实有主键,否则我将无法对它们进行插入(我在某处读过,如果我摆脱了主键,我将能够摆脱该异常,但是正如您所看到的,那不会在我的情况下工作)。

当我运行它时,我得到InsertAllOnSubmit 抛出的以下异常:

不允许在查询中显式构造实体类型“T_EDR_FILEBODY”。

我想我明白在查询中显式构造实体会出现问题。查询返回的实体具有更改跟踪,调用 submitchanges 时会将更改翻译到数据库中。但是,您如何将在客户端创建的实体上的更改转换到数据库中呢?但这真的意味着您永远无法使用 LINQ to SQL 执行 INSERT INTO...SELECT 类型的命令吗?

【问题讨论】:

  • 你能做一个“使用 _tx 作为新的 TransactionScope()”并将 ExecuteCommand 和其他任何东西包装起来吗?
  • 好吧,我想我可以,而且我可能只是很挑剔,但我很难接受你不能使用 linq 插入...select 语句。这将是一个巨大的便利帽。

标签: linq-to-sql bulkinsert


【解决方案1】:

你可以使用

ctx.Table1.InsertAllOnSubmit(
    mySelectEnumeration.Select(x => new Table1DT { ... })
);
  • InsertAllOnSubmit 将许多条目插入到 Linq to SQL 表中。
  • mySelectEnumeration 是选择要插入的项目的查询。
  • Select(new Table1DT { ... }) 是将您选择查询的数据类型转换为表的数据类型所需的转换。

您也可以使用ExecuteCommand 方法并手动管理事务。

using (var ctx = new DataClasses1DataContext()) {
    ctx.Connection.Open();
    using (ctx.Transaction = ctx.Connection.BeginTransaction()) {
        ctx.ExecuteCommand("sqlcommand");
        ctx.Transaction.Commit();
    }
}

或者使用事务范围:

using (var ctx = new DataClasses1DataContext()) {
    using (var scope = new TransactionScope()) {
        ctx.ExecuteCommand("sqlcommand");
        scope.Complete();
    }
}

【讨论】:

  • 我不确定我是否理解您的建议。我看不到如何根据 mySelectEnumeration 在内联构造函数上初始化 Table1DT 实例。我如何引用 mySelectEnumeration?或者,我尝试使用 Select 子句上的 Table1DT 内联构造函数将第一个查询(返回 IQueryable)封装在另一个查询中,因此返回 IQueryable。但是我得到了与将内联构造函数放在第一个查询中相同的错误:不允许在查询中显式构造实体类型“Table1DT”。
  • 由于我不知道您的具体 DataContext 类(在我的示例中为 ctx),因此我使用了占位符。 Table1 是表格中应插入的项目的占位符。 mySelectEnumeration 是您为选择要插入的项目而执行的查询的结果。 Table1DT 是您的Table1 的数据类型。而且,... 表示您必须在哪里设置“Table1”的属性,例如ID = x.identifier。如果不知道您的 DataContext,我无法更具体。
  • 好吧,我错了,我想我没有认真阅读您的回复(我错过了“x =>”)。好的,试过了,我在 InsertAllOnSubmit 调用上仍然遇到同样的异常:不允许在查询中显式构造实体类型“Table1DT”。 (我使用的符号与您使用的相同)。我读过这个,我知道由于某种原因你不能在查询中构造实体。不过不太明白为什么。
  • @Rui:你能把你的代码贴出来吗……很难猜到你在做什么。
猜你喜欢
  • 2012-01-23
  • 2014-04-23
  • 2023-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多