我正在尝试将以下存储过程转换为LinqToSql调用(这是SQL的简化版本):
INSERT INTO [MyTable]
([Name], [Value])
SELECT
@name, @value
WHERE
NOT EXISTS(SELECT [Value] FROM [MyTable] WHERE [Value] = @value)
DB对要检查的字段没有约束,因此在这种特定情况下,需要手动进行检查。此外,还有许多项目不断被插入,所以我需要确保当这个特定的插入发生时,没有值字段的欺骗。我的第一个预感是做以下事情:
using (TransactionScope scope = new TransactionScope())
{
if (Context.MyTables.SingleOrDefault(t => t.Value == in.Value) != null)
{
MyLinqModels.MyTable t = new MyLinqModels.MyTable()
{
Name = in.Name,
Value = in.Value
};
// Do some stuff in the transaction
scope.Complete();
}
}
这是我第一次遇到这种情况,所以我想确保以正确的方式进行。这看起来是否正确,或者任何人都可以提出一个更好的方法来解决这个问题而不需要两个单独的电话?
修改:我遇到类似的更新问题:
UPDATE [AnotherTable]
SET [Code] = @code
WHERE [ID] = @id AND [Code] IS NULL
我如何使用Linqtosql进行相同的检查?我假设我需要做一个get然后设置所有的值并提交,但是如果有人在执行更新时将[Code]更新为null以外的其他内容会怎么样?
与插入相同的问题......
答案 0 :(得分:1)
如果这是意外情况(即表示错误),则UNIQUE
约束就足够了。
没有直接方式通过LINQ-to-SQL执行此操作,因此您的TransactionScope
(或传入的连接上的SqlTransaction
)是 可行的机制。另一个可能是一个替代触发器,或者是执行INSERT
的存储过程。
你所拥有的可能是最简单的;看它是否足够快(它有一个额外的往返)并坚持下去?
答案 1 :(得分:1)
我不相信LINQ-to-SQL可行,但更好的选择是使用Any()
代替SingleOrDefault()
:
using (TransactionScope scope = new TransactionScope())
{
if (!Context.MyTables.Any(t => t.Value == in.Value))
{
MyLinqModels.MyTable t = new MyLinqModels.MyTable()
{
Name = in.Name,
Value = in.Value
};
// Do some stuff in the transaction
scope.Complete();
}
}
我相信Any()
在SQL中使用EXISTS
关键字,它选择布尔值而不是该行中所有列的完整内容。
Aaron建议使用存储过程可能会更直接 - 您也可以将其连接到您的datacontext。
答案 2 :(得分:1)
如果数据库中没有唯一约束,则将此包含在TransactionScope
中实际上不会阻止冲突。它只保证此事务的原子性。
在开始更新之前,完全有可能并且可能在高容量场景中让两个同时发生的事务通过第一次null
检查(这只是一个读取)。在数据库中强制执行唯一性约束非常重要 - 如果你不能在这里做到这一点,那么你就可以为你做好工作了。
老实说,根据您的要求,我建议改为使用存储过程。 Linq to SQL是一个很棒的工具,但它无法执行SQL所能实现的所有;这似乎是需要比L2S更能控制的情况之一。