Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework - redundant connection string

I'm using Entity Framework 4 in my project. The Framework has created its own connection string, so my web.config connectionStrings section file looks following:

  <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=&quot;Data Source=localhost;Initial Catalog=VNK;User ID=user;Password=pass;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />
  </connectionStrings>

The first connection string called ApplicationServices is my original one. The second, called VNKEntities has been created while generating the model.

When I checked the generated *.edmx file, I found that this model is referencing its connection string, which is shown below:

    /// <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();
    }

My question is how can I get rid of the VNKEntities connection string, and leave only ApplicationServices, to which I will be referencing from my model? I would like to have only one connection string to the database, because I'm using only one database (replacing the constructor parameter from name=VNKEntities to name=ApplicationServices is not working).

Regards

like image 803
jwaliszko Avatar asked Sep 23 '10 11:09

jwaliszko


4 Answers

Although you can create the connection in code, as @gandjustas points out (+1), you cannot get away from having a connection string or EntityConnection.

This is because it is not actually redundant. Yes, the database connection part is redundant, and @gandjustas showed you how to remove that redundancy. However, the entity framework connection string also contains information about your model, which is not found anywhere in the connection string you wish to keep. This model information has to come from somewhere. Were you to eliminate the entity framework's connection string and use the parameter list constructor on ObjectContext, you would have eliminated all references to the model.

like image 93
Craig Stuntz Avatar answered Nov 12 '22 15:11

Craig Stuntz


  1. Manualy create DbConnection from ordinary connection string
  2. Manualy create MetadataWorkspace object.
  3. Create EntityConnection using this ctor.
  4. Pass entity connection to ObjectContext constructor.
like image 20
gandjustas Avatar answered Nov 12 '22 15:11

gandjustas


I had the same problem. I have solved it by following way:

I have created two edmx file, but while creating second edmx file, i ignored the connection string to be save in config file. This way my config file will hold only one Connection string. Then i modified following lines in my connection string:

<add name="MyDbContext" connectionString="metadata=res://*/;provider=System.Data.SqlClient;provider connection string=&quot;data source=abc;initial catalog=mydb;persist security info=True;user id=myuser;password=password;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />

Just replace "res://model1.csdl" with "res://*/" and it works like a charm.

You can specify this connection name in constructor of your dbcontext class like:

public MyDbContext() : base("name=NameOfYourConnectionString") //  Name of your connection string
{ }

Note: I am using Entity Framework 5.0.

like image 34
SoftSan Avatar answered Nov 12 '22 16:11

SoftSan


I'll provide complete implementation I did to resolve this issue (based on gandjustas hints). I've written a simple wrapper for the context, which can be used in the following manner:

using (var wrapper = new ContextWrapper<VNKEntities>())
{
    // do your stuff based on wrapper.Context
}

Type ContextWrapper is a template which simply wraps the context which is just constructed in a slightly other way (using only one connection string) and then exposed by property. Its internal implementation is placed below:

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;
    }
}

You can see the usage of custom class named 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;
    }
}

So now you can have one connection string:

<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>

and metadata defined in app settings section (the second key points to assembly where your domain model is actually stored):

<appSettings>
  <add key="MetadataWorkspacePaths" value="res://*/VNKModel.csdl|res://*/VNKModel.ssdl|res://*/VNKModel.msl" />
  <add key="MetadataAssemblyNameToConsider" value="VNK.Models" />
</appSettings>

The logic for type Setting is straightforward, as it just pulls out the settings from configuration file.

like image 1
jwaliszko Avatar answered Nov 12 '22 16:11

jwaliszko