Entity Framework - избыточная строка подключения
Я использую Entity Framework 4 в своем проекте. Framework создал свою собственную строку подключения, поэтому мой web.config
Файл раздела connectionStrings выглядит следующим образом:
<connectionStrings>
<add name="ApplicationServices" connectionString="data source=localhost;user id=user;pwd=pass;initial catalog=VNK" providerName="System.Data.SqlClient" />
<add name="VNKEntities" connectionString="metadata=res://*/VNKModel.csdl|res://*/VNKModel.ssdl|res://*/VNKModel.msl;provider=System.Data.SqlClient;provider connection string="Data Source=localhost;Initial Catalog=VNK;User ID=user;Password=pass;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
</connectionStrings>
Первая строка подключения называется ApplicationServices
мой оригинальный. Второй называется VNKEntities
был создан при создании модели.
Когда я проверил сгенерированный файл *.edmx, я обнаружил, что эта модель ссылается на строку подключения, как показано ниже:
/// <summary>
/// Initializes a new VNKEntities object using the connection string found in the 'VNKEntities' section of the application configuration file.
/// </summary>
public VNKEntities() : base("name=VNKEntities", "VNKEntities")
{
this.ContextOptions.LazyLoadingEnabled = true;
OnContextCreated();
}
Мой вопрос, как я могу избавиться от VNKEntities
Строка подключения, и оставить только ApplicationServices
на что я буду ссылаться из моей модели? Я хотел бы иметь только одну строку подключения к базе данных, потому что я использую только одну базу данных (заменяя параметр конструктора из name=VNKEntities
в name=ApplicationServices
не работает).
С уважением
4 ответа
- Вручную создать DbConnection из обычной строки подключения
- Ручное создание объекта MetadataWorkspace.
- Создайте EntityConnection, используя этот ctor.
- Передайте соединение сущности конструктору ObjectContext.
Хотя вы можете создать соединение в коде, как указывает @gandjustas (+1), вы не можете избежать наличия строки соединения или EntityConnection
,
Это потому, что это на самом деле не избыточно. Да, часть соединения с базой данных является избыточной, и @gandjustas показал вам, как удалить эту избыточность. Тем не менее, строка соединения сущности также содержит информацию о вашей модели, которую нет нигде в строке соединения, которую вы хотите сохранить. Эта модель информации должна откуда-то прийти. Если бы вы удалили строку подключения структуры сущностей и использовали конструктор списка параметров в ObjectContext
Вы бы устранили все ссылки на модель.
Я предоставлю полную реализацию, которую я сделал, чтобы решить эту проблему (на основе подсказок gandjustas). Я написал простую оболочку для контекста, которую можно использовать следующим образом:
using (var wrapper = new ContextWrapper<VNKEntities>())
{
// do your stuff based on wrapper.Context
}
Тип ContextWrapper
это шаблон, который просто оборачивает контекст, который только что построен немного другим способом (используя только одну строку подключения), а затем предоставляется свойством. Его внутренняя реализация размещена ниже:
public class ContextWrapper<TContext> : IDisposable
where TContext : ObjectContext
{
private TContext _context;
private EntityConnectionManager _manager;
private bool _disposed;
public ContextWrapper()
: this(true)
{
}
public ContextWrapper(bool lazyLoadingEnabled)
{
_disposed = false;
_manager = new EntityConnectionManager();
_context = (TContext)Activator.CreateInstance(typeof(TContext), _manager.Connection);
_context.ContextOptions.LazyLoadingEnabled = lazyLoadingEnabled;
}
~ContextWrapper()
{
Dispose(false);
}
public TContext Context
{
get { return _context; }
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
if (_manager != null)
{
_manager.Dispose();
_manager = null;
}
var ctx = _context as IDisposable;
if (ctx != null)
{
ctx.Dispose();
_context = null;
}
}
}
_disposed = true;
}
}
Вы можете увидеть использование пользовательского класса с именем EntityConnectionManager
:
internal class EntityConnectionManager : IDisposable
{
private DbConnection _connection;
private EntityConnection _entityConnection;
private volatile bool _disposed;
public EntityConnectionManager()
{
var workspace = new MetadataWorkspace(Setting.MetadataWorkspacePaths.Split('|'), new[] { Assembly.ReflectionOnlyLoad(Setting.MetadataAssemblyNameToConsider) });
_connection = new SqlConnection(Setting.ConnectionString);
_entityConnection = new EntityConnection(workspace, _connection);
_disposed = false;
}
public EntityConnection Connection
{
get { return _entityConnection; }
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
if (_connection != null)
{
_connection.Dispose();
_connection = null;
}
if (_entityConnection != null)
{
_entityConnection.Dispose();
_entityConnection = null;
}
}
}
_disposed = true;
}
}
Так что теперь вы можете иметь одну строку подключения:
<connectionStrings>
<add name="ApplicationServices" connectionString="data source=localhost;user id=user;pwd=pass;initial catalog=VNK;Pooling=False;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
</connectionStrings>
и метаданные, определенные в разделе настроек приложения (второй ключ указывает на сборку, где фактически хранится ваша модель домена):
<appSettings>
<add key="MetadataWorkspacePaths" value="res://*/VNKModel.csdl|res://*/VNKModel.ssdl|res://*/VNKModel.msl" />
<add key="MetadataAssemblyNameToConsider" value="VNK.Models" />
</appSettings>
Логика для типа Setting
это просто, так как он просто вытаскивает настройки из файла конфигурации.
У меня такая же проблема. Я решил это следующим образом:
Я создал два файла EDMX, но при создании второго файла EDMX, я проигнорировал строку подключения для сохранения в файле конфигурации. Таким образом, мой файл конфигурации будет содержать только одну строку подключения. Затем я изменил следующие строки в строке подключения:
<add name="MyDbContext" connectionString="metadata=res://*/;provider=System.Data.SqlClient;provider connection string="data source=abc;initial catalog=mydb;persist security info=True;user id=myuser;password=password;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
Просто замените "res://model1.csdl" на "res://*/", и это работает как шарм.
Вы можете указать это имя соединения в конструкторе вашего класса dbcontext, например:
public MyDbContext() : base("name=NameOfYourConnectionString") // Name of your connection string
{ }
Примечание. Я использую Entity Framework 5.0.