Управление соединениями
На этой странице описывается поведение Entity Framework относительно передачи подключений к контексту и функциональным возможностям Database.ПодключениеИонный. Open() API.
Передача Подключение в контекст
Поведение для EF5 и более ранних версий
Существует два конструктора, которые принимают подключения:
public DbContext(DbConnection existingConnection, bool contextOwnsConnection)
public DbContext(DbConnection existingConnection, DbCompiledModel model, bool contextOwnsConnection)
Их можно использовать, но вам придется обойти несколько ограничений:
- Если вы передаете открытое подключение к одному из них, то при первом попытке платформы использовать его в InvalidOperationException возникает сообщение о том, что он не может повторно открыть уже открытое соединение.
- Флаг contextOwns Подключение ion интерпретируется, чтобы означать, следует ли удалять подключение к базовому хранилищу при удалении контекста. Но независимо от этого параметра подключение хранилища всегда закрывается при удалении контекста. Таким образом, если у вас несколько DbContext с тем же подключением, какое бы контекст ни было удалено, сначала закроет соединение (аналогично, если вы смешали существующее ADO.NET соединение с DbContext, DbContext всегда закрывает соединение при удалении).
Можно обойти первое ограничение, приведенное выше, передав закрытое соединение и только выполнив код, который откроет его после создания всех контекстов:
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.EntityClient;
using System.Linq;
namespace ConnectionManagementExamples
{
class ConnectionManagementExampleEF5
{
public static void TwoDbContextsOneConnection()
{
using (var context1 = new BloggingContext())
{
var conn =
((EntityConnection)
((IObjectContextAdapter)context1).ObjectContext.Connection)
.StoreConnection;
using (var context2 = new BloggingContext(conn, contextOwnsConnection: false))
{
context2.Database.ExecuteSqlCommand(
@"UPDATE Blogs SET Rating = 5" +
" WHERE Name LIKE '%Entity Framework%'");
var query = context1.Posts.Where(p => p.Blog.Rating > 5);
foreach (var post in query)
{
post.Title += "[Cool Blog]";
}
context1.SaveChanges();
}
}
}
}
}
Второе ограничение просто означает, что необходимо воздержаться от удаления любого из объектов DbContext, пока вы не будете готовы к закрытию подключения.
Поведение в EF6 и будущих версиях
В EF6 и будущих версиях DbContext имеет одинаковые два конструктора, но больше не требуется, чтобы соединение, переданное конструктору, закрывалось при получении. Таким образом, теперь это возможно:
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Linq;
using System.Transactions;
namespace ConnectionManagementExamples
{
class ConnectionManagementExample
{
public static void PassingAnOpenConnection()
{
using (var conn = new SqlConnection("{connectionString}"))
{
conn.Open();
var sqlCommand = new SqlCommand();
sqlCommand.Connection = conn;
sqlCommand.CommandText =
@"UPDATE Blogs SET Rating = 5" +
" WHERE Name LIKE '%Entity Framework%'";
sqlCommand.ExecuteNonQuery();
using (var context = new BloggingContext(conn, contextOwnsConnection: false))
{
var query = context.Posts.Where(p => p.Blog.Rating > 5);
foreach (var post in query)
{
post.Title += "[Cool Blog]";
}
context.SaveChanges();
}
var sqlCommand2 = new SqlCommand();
sqlCommand2.Connection = conn;
sqlCommand2.CommandText =
@"UPDATE Blogs SET Rating = 7" +
" WHERE Name LIKE '%Entity Framework Rocks%'";
sqlCommand2.ExecuteNonQuery();
}
}
}
}
Кроме того, флаг contextOwns Подключение ion теперь определяет, закрывается ли соединение и удаляется при удалении DbContext. Таким образом, в приведенном выше примере подключение не закрывается при удалении контекста (строка 32), так как оно было бы в предыдущих версиях EF, а не при удалении самого подключения (строка 40).
Конечно, dbContext по-прежнему может контролировать соединение (просто задать contextOwns Подключение ion значение true или использовать один из других конструкторов, если это необходимо.
Примечание.
При использовании транзакций с этой новой моделью существуют некоторые дополнительные рекомендации. Дополнительные сведения см. в разделе "Работа с транзакциями".
Базы данных. Подключение. Open()
Поведение для EF5 и более ранних версий
В EF5 и более ранних версиях возникает ошибка, так что объект ObjectContext.ПодключениеИонный. Состояние не было обновлено, чтобы отразить истинное состояние подключения к базовому хранилищу. Например, если вы выполнили следующий код, можно вернуть состояние "Закрыто", хотя на самом деле подключение к базовому хранилищу открыто.
((IObjectContextAdapter)context).ObjectContext.Connection.State
Отдельно, если вы открываете подключение к базе данных, вызывая базу данных. Подключение. Open() он будет открыт до следующего момента выполнения запроса или вызова чего-либо, для которого требуется подключение к базе данных (например, SaveChanges()), но после этого базовое подключение хранилища будет закрыто. Затем контекст повторно открывается и повторно закрывает подключение в любой момент, когда требуется другая операция базы данных:
using System;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.EntityClient;
namespace ConnectionManagementExamples
{
public class DatabaseOpenConnectionBehaviorEF5
{
public static void DatabaseOpenConnectionBehavior()
{
using (var context = new BloggingContext())
{
// At this point the underlying store connection is closed
context.Database.Connection.Open();
// Now the underlying store connection is open
// (though ObjectContext.Connection.State will report closed)
var blog = new Blog { /* Blog’s properties */ };
context.Blogs.Add(blog);
// The underlying store connection is still open
context.SaveChanges();
// After SaveChanges() the underlying store connection is closed
// Each SaveChanges() / query etc now opens and immediately closes
// the underlying store connection
blog = new Blog { /* Blog’s properties */ };
context.Blogs.Add(blog);
context.SaveChanges();
}
}
}
}
Поведение в EF6 и будущих версиях
Для EF6 и будущих версий мы приняли подход, который, если вызывающий код выбирает открытие подключения путем вызова контекста. Базы данных. Подключение. Затем open() он имеет хорошую причину для этого, и платформа предполагает, что он хочет контролировать открытие и закрытие подключения и больше не будет закрывать подключение автоматически.
Примечание.
Это может привести к подключениям, которые открыты в течение длительного времени, поэтому используйте с осторожностью.
Мы также обновили код, чтобы ObjectContext. Подключение. Теперь состояние отслеживает состояние базового подключения правильно.
using System;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Core.EntityClient;
using System.Data.Entity.Infrastructure;
namespace ConnectionManagementExamples
{
internal class DatabaseOpenConnectionBehaviorEF6
{
public static void DatabaseOpenConnectionBehavior()
{
using (var context = new BloggingContext())
{
// At this point the underlying store connection is closed
context.Database.Connection.Open();
// Now the underlying store connection is open and the
// ObjectContext.Connection.State correctly reports open too
var blog = new Blog { /* Blog’s properties */ };
context.Blogs.Add(blog);
context.SaveChanges();
// The underlying store connection remains open for the next operation
blog = new Blog { /* Blog’s properties */ };
context.Blogs.Add(blog);
context.SaveChanges();
// The underlying store connection is still open
} // The context is disposed – so now the underlying store connection is closed
}
}
}