【发布时间】: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 语句。这将是一个巨大的便利帽。