В моей программе EF4 у меня есть таблица Applicant и Application. Несколько экземпляров программы периодически запускаются для создания приложений для заявителей на основе некоторой бизнес-логики. В таблице приложений у меня не может быть более одной записи Submitted/BeingSubmitted для заявителя.
Итак, вот фрагмент кода, который проверяет наличие приложения Submitted/BeingSubmitted и вставляет его. Он запускается внутри цикла foreach для списка кандидатов.
public Application SaveApplication(Int32 applicantId)
{
using (TransactionScope txScope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
if (ApplicantHasPendingApplication(applicantId))
return null;
Application app = null;
try
{
app = new Application()
{
// Create the object...
};
_unitOfWork.DisclosureApplications.Add(app);
_unitOfWork.Commit();
_unitOfWork.Refresh(app); // We save and refresh it to get the Id.
txScope.Complete();
}
catch (UpdateException ex)
{
// We get an Update exception here when multiple instances tries to insert Application.
}
return app;
}
}
Приведенный выше фрагмент кода предотвращает вставку повторяющихся записей, за исключением того факта, что он создает исключение UpdateException при запуске нескольких экземпляров программы. Если я проглочу это исключение и продолжу, то все в порядке.
Тем не менее, я попытался протестировать/запустить приведенный выше код параллельно, но он вставляет повторяющиеся записи в базу данных.
Parallel.Invoke(
() => CreateApplications("Parallel Instance 1"),
() => CreateApplications("Parallel Instance 2"));
private void CreateApplications(String dummyInstanceName)
{
var unitOfWork = new SqlUnitOfWork();
var applicants = unitOfWork.Applicants.FindAll().Take(100).ToList();
var facade = new ProviderFacade(unitOfWork, new Log4NetLogger(dummyInstanceName));
foreach (Applicant applicant in applicants)
{
facade.ApplicationProvider.SaveApplication(applicant.applicantID);
}
}
В приведенном выше фрагменте кода он выдает UpdateException и вставляет несколько строк приложения для заявителя.
Обратите внимание, что таблица имеет только суррогатный первичный ключ и никаких других уникальных ограничений.
Мой вопрос: почему TransactionScope вставляет повторяющиеся строки, запуская его в Parallel.Invoke, но не когда я запускаю несколько экземпляров программы? Каким будет разумный подход к ее достижению?
Обновление: ctor SqlUnitOfWork
public SqlUnitOfWork()
{
_context = new MyEntities();
}
Ctor MyEntities генерируется EF -
public const string ConnectionString = "name=Entities";
public const string ContainerName = "Entities";
public TPIEntities() : base(ConnectionString, ContainerName)
{
this.ContextOptions.LazyLoadingEnabled = true;
}
Спасибо.