Подтвердить что ты не робот

С#, работающий с Entity Framework на многопоточном сервере

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

4b9b3361

Ответ 1

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

  • Не используйте уникальный контекст с locks (no singleton pattern)
  • Предоставить службы без учета состояния (вам нужно создать экземпляр и установить один контекст на запрос)
  • Сократить время жизни контекста как можно больше
  • Внедрить concurrency -control system. Оптимистичный concurrency может быть легко реализован с помощью Entity Framework (how-to). Это гарантирует, что вы не будете перезаписывать изменения в БД при использовании сущности, которая не обновляется

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

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

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

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

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

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

Ответ 2

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

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

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

Ответ 3

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

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

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

Ответ 4

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

Ответ 5

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

Более подробную информацию вы найдете в большой статье. http://www.west-wind.com/weblog/posts/2008/Feb/05/Linq-to-SQL-DataContext-Lifetime-Management

Хорошие книги: 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 Lifetime в сценарии привязки WinForm

Ответ 6

Я использую инфраструктуру сущности в многопоточной среде, где любой поток, ui и background (как 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;