c # работа с Entity Framework на многопоточном сервере - PullRequest
40 голосов
/ 23 февраля 2012

Какова лучшая практика для работы со структурой сущностей на многопоточном сервере?Я использую инфраструктуру сущностей ObjectContext для управления всеми своими действиями с базой данных, теперь я знаю, что этот контекст не является потокобезопасным, поэтому сейчас, когда мне нужно использовать его для выполнения некоторых действий с БД, я окружаю его оператором lock длябыть в безопасности.Это как я должен это сделать ??

Ответы [ 6 ]

69 голосов
/ 23 февраля 2012

Несколько полезных советов для Entity Framework в многопоточной среде:


Я немного запутался, я думал, чтоиспользование одного контекста хорошо, потому что, по моему мнению, он делает некоторые выводы, поэтому, когда я имею дело с одной и той же сущностью в последовательных запросах, гораздо быстрее будет использовать один и тот же контекст, чем каждый раз создавать новый контекст.Так почему же полезно использовать его следующим образом, если он медленнее и все же не безопасен для потоков?

Вы могли бы использовать только один контекст, но это настоятельно не рекомендуется , если выдействительно знаю, что вы делаете .

Я вижу две основные проблемы, которые часто случаются при таком подходе:

  1. вы будете использовать много памяти какваш контекст никогда не будет удален, и все манипулируемые сущности будут кэшироваться в памяти (каждая сущность, которая появляется в результате запроса, кэшируется).

  2. вы столкнетесь с множеством проблем параллелизмаесли вы измените свои данные из другой программы / контекста.Например, если вы изменяете что-то непосредственно в своей базе данных, и связанный объект уже был кэширован в вашем уникальном объекте контекста, ваш контекст никогда не узнает об изменении , которое было сделано непосредственно в базе данных.Вы будете работать с кэшированной сущностью, которая не обновлена, и, поверьте мне, это приведет к трудностям, которые трудно найти и исправить.

Также не беспокойтесь о производительности использования нескольких контекстов : накладные расходы на создание / удаление нового контекста для запроса почти невелики в 90% случаев использования.Помните, что создание нового контекста не обязательно создает новое соединение с базой данных (поскольку база данных обычно использует пул соединений).

12 голосов
/ 23 февраля 2012

Это как я должен это сделать?

Нет. Как минимум, используйте контекст для потока, но я настоятельно рекомендую вам рассматривать контекст как единицу работы и, таким образом, использовать контекст для единицы работы для потока.

Вам решать, как определить «единицу работы» для вашего приложения. Но не используйте lock для использования контекста в нескольких потоках. Это не масштабируется.

5 голосов
/ 23 февраля 2012

Вы рассматриваете ObjectContext, как будто он является чрезвычайно дорогостоящим объектом, поэтому вы создаете экземпляр один раз, а затем рассматриваете его как «фасад». Там нет необходимости делать это. Если по какой-либо другой причине соединения объединяются под капотом и стоят очень мало (микросекунда? - вероятно, меньше?) Полной настройки «цепочки объектов» для использования абстракции ObjectContext.

ObjectContext, очень похожий на прямое использование SqlConnection и т. Д., Предназначен для использования с методологией "как можно более поздней реализации и сброса как можно скорее".

EF дает вам некоторую безопасность в том, что у вас есть возможность проверить, есть ли у вас новейшие объекты до совершения (Optimistic Concurrency). Это не означает «потокобезопасность» как таковое, но оно выполняет то же самое, если вы уважаете правила.

2 голосов
/ 23 февраля 2012

Обычно ObjectContext не должен использоваться глобально во всем приложении. Вы должны часто создавать новые ObjectContexts и утилизировать старые. Они, конечно же, не безопасны. Если вы продолжаете использовать один и тот же ObjectContext (в зависимости от времени жизни вашего приложения), легко получить исключение нехватки памяти, если вы изменяете огромные объемы данных, поскольку ссылки на изменяемые объекты хранятся в контексте объекта. *

1 голос
/ 23 февраля 2012

Я создаю новый Контекст для каждой атомарной операции и располагаю контекст. Насколько я знаю по книгам и статьям, я предпочитаю максимально сократить время жизни в Context. (но это зависит от вашего подхода и типа приложения, winform или web)

Более подробную информацию вы найдете в отличной статье. http://www.west -wind.com / блог / сообщений / 2008 / Февраль / 05 / Linq к SQL-DataContext-Lifetime-менеджмент

Хорошие книги: http://books.google.co.th/books?id=Io7hHlVN3qQC&pg=PA580&lpg=PA580&dq=DbContext+lifetime+for+desktop+application&source=bl&ots=ogCOomQwEE&sig=At3G1Y6AbbJH7OHxgm-ZvJo0Yt8&hl=th&ei=rSlzTrjAIovOrQeD2LCuCg&sa=X&oi=book_result&ct=result&resnum=2&ved=0CCgQ6AEwAQ#v=onepage&q&f=false

Существующее обсуждение на Время жизни Datacontext в сценарии привязки WinForm

0 голосов
/ 17 февраля 2016

Я использую Entity Framework в многопоточной среде, где любой поток, пользовательский интерфейс и фон (STA и MTA) могут одновременно обновлять одну и ту же базу данных. Я решил эту проблему, заново создав соединение сущностей с нуля в начале использования в любом новом фоновом потоке. Изучение экземпляра соединения сущности ConnectionString показывает руководство читателя, которое, как я полагаю, используется для связи общих экземпляров соединения. При воссоздании соединения сущностей с нуля значения guid различны для каждого потока, и никакого конфликта, по-видимому, не возникает. Обратите внимание, что сборка должна быть такой же, как и у модели.

public static EntityConnection GetEntityConnection(
// Build the connection string.

  var sqlBuilder = new SqlConnectionStringBuilder();
  sqlBuilder.DataSource = serverName;
  sqlBuilder.InitialCatalog = databaseName;
  sqlBuilder.MultipleActiveResultSets = true;
  ...
  var providerString = sqlBuilder.ToString();
  var sqlConnection = new SqlConnection(providerString);

// Build the emtity connection.

  Assembly metadataAssembly = Assembly.GetExecutingAssembly();
  Assembly[] metadataAssemblies = { metadataAssembly };
  var metadataBase = @"res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl";
  var dbModelMetadata = String.Format(metadataBase, objectContextTypeModelName);
  // eg: "res://*/Models.MyDatabaseModel.csdl|res://*/Models.MyDatabaseModel.ssdl|res://*/Models.MyDatabaseModel.msl"
  var modelMetadataPaths = modelMetadata.Split('|');
  var metadataWorkspace = new MetadataWorkspace(modelMetadataPaths, metadataAssemblies);
  var entityDbConnection = new EntityConnection(metadataWorkspace, sqlConnection);
  return entityDbConnection;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...