6

我试图弄清楚是否可以使用 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 类型的命令吗?

4

1 回答 1

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();
    }
}
于 2010-03-02T16:17:07.200 回答