нам здесь неясно, нужна ли нам транзакция в следующем сценарии, если мы используем ConcurrencyMode = фиксированный или нет.
3 таблицы задействованы:
<User>
UserID (pk, int)
SessionToken (uniqueidentifier, nullable, FK onto Session table, in EDMX set to ConcurrencyMode=fixed)
<Journal>
JournalID (PK, int)
SessionID (int, FK onto Session table)
JournalAction (varchar(256))
<Session>
SessionID (pk, int)
SessionToken (uniqueidentifier, nullable)
SessionEndTimestamp (datetime, nullable)
Итак, что происходит,когда мы делаем «выход из системы», нам необходимо:
- установить для Session.SessionEndTimeStamp значение DateTime.Now
- установить для User.SessionToken значение NULL (в настоящее время оно будет установлено равнымзапись нашего Session.SessionToken, чьей записью мы только что манипулировали на шаге 1.)
- добавить запись в журнале (в эту сессию)
Мы хотим, чтобы это происходило ТОЛЬКО в случае, если никто другойдо сих пор манипулировал User.SessionToken.В случае, если кто-то другой манипулировал им, это должно привести к сбою таким образом, что ни один из трех упомянутых шагов не будет сохранен в БД.
Мы используем EF 6.1.3.Теперь вопрос в том, сможет ли EF надежно прервать сохранение (без использования транзакции), если мы будем использовать только один контекст, как показано в приведенном ниже коде.
Код будет:
using (var context = new xxxEntities())
{
var session = context.Sessions.First(x => x.SessionToken == tokenToLogout);
var user = context.Users.First(p => p.UserID == userID);
if (user.SessionToken == null)
throw new Exception("cannot logout, currently not logged in");
if (user.SessionToken != tokenToLogout)
throw new Exception("cannot logout, wrong token provided");
//the 3 write operations that either all should be completed or none written at all in case somebody manipulated user.SessionToken in the meantime
session.SessionEndTimeStamp = DateTime.Now; //#1: update
user.SessionToken = null; //#2: update
context.Journals.Add(new Journal(){Session = session, JournalAction="logout happened"}); //#3: insert
context.SaveChanges();
}
Я знаю, что если что-то изменится User.SessionToken между тем, будет выброшено исключение из-за установки на User.SessionToken значения ConcurrencyMode = fixed, НО я не уверен, если это МОЖЕТ означать этот сеанс.SessionEndTimeStamp уже зафиксирован в базе данных или запись в журнале уже сделана?
До сих пор у нас была транзакция, связанная с этим, и мы единственные, кто в данный момент манипулирует, но мы обсуждаем удалениетранзакции, где это возможно, и была идея об установке user.SessionToken в ConcurrencyMode = исправлено.Аргумент заключается в том, что мы просто выполняем один «SaveChanges ()», поэтому EF должен обрабатывать, что либо все, либо ничего не сохраняется.
Но я думаю, нам нужна транзакция здесь, иначе не гарантируется, чтополный «откат» произойдет?