EF4, TransactionScope и Task <> - PullRequest
       23

EF4, TransactionScope и Task <>

4 голосов
/ 09 декабря 2011

Можно ли открыть TransactionScope, запустить асинхронную Task с загрузкой, которая работает на EF4 ObjectContext, и затем зафиксировать результат?

Как определяется текущая область транзакциив EF4?Произойдет ли это, если / когда задача будет запланирована в другом потоке, отличном от области транзакции?

Ответы [ 2 ]

4 голосов
/ 10 декабря 2011

Да, это так.Для начала, Entity Framework просто использует провайдера (по умолчанию System.Data.SqlClient), который выберет «окружающий» контекст транзакции из потока, который выполняется.Таким образом, единственная хитрость - это распространение одной транзакции на Tasks, которую вы увеличиваете.Я объяснил, как вы можете сделать это здесь, в этом посте .

В то время как этот пост был больше посвящен распространению порожденных задач PLINQ, такой же подход применим, если вы вручную раскручиваете свою собственную Tasks.Если вам нужен пример кода, пожалуйста, дайте мне основные сведения о том, как именно будет работать ваш Task, чтобы я мог привести хороший пример кода.

0 голосов
/ 28 января 2013

Нет, вы не можете (с пользой) сделать это.

Хотя ответ Дрю Марша верен (что существуют средства для того, чтобы сделать транзакцию межпотоковой), это вам не поможет.ObjectContext не является потокобезопасным - вам не следует обращаться к нему из других потоков, и вы должны определенно не обновлять его в других потоках;у вас будет неопределенное поведение: вы, вероятно, столкнетесь с повреждением данных, которое (если вам повезет) приведет к сбоям.

Если вам нужен многопоточный доступ ObjectContext, вам нужно вручную сериализовать доступы, например, с помощью блокировок.Но если вы сделаете это, вы можете просто получить доступ к контексту из одного потока;обычно это проще и почти всегда быстрее - и тогда у вас не возникнет проблем с транзакциями.

Если вы настаиваете на ручной синхронизации доступа к ObjectContext вместо использования потока, вы также можете использовать простойCommittableTransaction и передать это по простоте, а не использовать внешнюю транзакцию;так как вам все равно придется вручную управлять транзакцией, это более понятно сделать с помощью явного дескриптора объекта, а не хитрых переходов состояний (где точные детали того, какой поток выполняет то, что важно, но не явно в коде).

Кстати, если вы все же используете транзакцию окружения, я был бы осторожен с планированием задач, особенно с асинхронной функцией C # 5, так как вам может потребоваться четко знать, когда выполнение может изменить поток (Я никогда не пробовал этого, поэтому я не могу дать вам никаких указателей, к сожалению).

Резюме: просто не делайте этого: вы не получаете параллелизм благодаря многопоточности из-за ограничений ObjectContext (и на практике, БД), так что вы могли бы также оставить одну транзакцию в одном потоке и сохранить ее простотой.Будущие сопровождающие будут благодарить вас за ясность.

...