Как установить точки сохранения для Linq в SQL и использовать "НЕТ" ExecuteCommand?
TransactionScope TransactionABC = new TransactionScope();
try
{
context.Connection.Open();
{
context.ExecuteCommand("insert into test (test) values (1)")
context.SubmitChanges();
context.ExecuteCommand("savepoint test");
context.ExecuteCommand("insert into test (test) values (2)")
context.SubmitChanges();
context.ExecuteCommand("rollback to test");
}
TransactionABC.Complete();
TransactionABC.Dispose();
}
catch (Exception ec)
{
MessageBox.Show(" ", ec.Message);
}
finally
{
context.Connection.Close();
}
Это работает, но только с ExecuteCommand. Я хочу использовать функцию, потому что я не вижу, что происходит в точке сохранения!
2 ответа
Я бы посоветовал просто не делать этого. Это не обязательно то, что вы хотите услышать, но особенно при смешивании с TransactionScope
точки сохранения не очень хорошая идея. TransactionScope
s может быть вложенным, но первый откат обрекает все, а фиксация происходит только в самой внешней транзакции.
В большинстве сценариев, о которых я могу подумать, лучше сначала очистить данные. Вы можете (и должны) также использовать ограничения для сети безопасности, но если вы попали в эту сеть безопасности, допустите большие проблемы и откатите все.
Пример вложенных транзакций:
public void DebitCreditAccount(int accountId, decimal amount, string reference)
{
using(var tran = new TransactionScope())
{
// confirm account exists, and update estimated balance
var acc = db.Accounts.Single(a => a.Id == accountId);
acc.BalanceEstimate += amount;
// add a transaction (this defines the **real** balance)
db.AccountTransactions.InsertOnSubmit(
new AccountTransaction {
AccountId = accountId, Amount = amount,
Code = amount >= 0 ? "C" : "D",
Reference = reference });
db.SubmitChanges();
tran.Complete();
}
}
public void Transfer(int fromAccountId, int toAccountId,
decimal amount, string reference)
{
using(var tran = new TransactionScope())
{
DebitCreditAccount(fromAccountId, -amount, reference);
DebitCreditAccount(toAccountId, amount, reference);
tran.Complete();
}
}
В приведенном выше DebitCreditAccount
является атомарным - мы либо добавим учетную запись-транзакцию и обновим оценочный баланс, либо ничего. Если это единственная транзакция, то она фиксируется в конце этого метода.
Однако в Transfer
метод, мы создаем еще одну внешнюю транзакцию; мы либо выполним оба DebitCreditAccount
или нет. Здесь внутренний tran.Complete()
(в DebitCreditAccount
) не фиксирует db-транзакцию, поскольку существует внешняя транзакция. Это просто говорит: "Я счастлив". И наоборот, если любая из внутренних транзакций будет прервана (Dispose()
звонил без Complete()
), то внешняя транзакция немедленно откатывается, и эта транзакция откажется от любой дополнительной работы. Внешняя транзакция фиксируется, только если внутренняя транзакция не была прервана, и Complete()
вызывается на внешней транзакции.
Как насчет ExecuteQuery?
С DataContext.ExecuteQuery вы отправляете текст в базу данных, как ExecuteCommand, но вы можете получить результаты запроса обратно из этого текста.
IEnumerable<int> results = ExecuteQuery<int>(@"
DECLARE @Table TABLE(Id int)
INSERT INTO @Table SELECT {0}
INSERT INTO @Table SELECT {1}
SELECT Id FROM Table", 101, -101);
IEnumerable<Customer> results = ExecuteQuery<Customer>( @"
Rollback transaction
SELECT *
FROM Customer
WHERE ID = {0}", myId);