Entity Framework Object not allowing Connection String to be passed as parameter - entity-framework

I am trying to initialize an Entity object (ADO.NET EF Object), but it does not allow me to choose what connection string I want to use. I need to change connection string in order to give different access levels to users.
There are no overrides in the Entities Object, just a parameterless constructor.
If anyone can give me any pointers, it is appreciated.

If you have used the designer to generate an .edmx file for you, you will have something like below:
public MyEntities() : base("name=MyEntities", "MyEntities")
{
this.ContextOptions.LazyLoadingEnabled = true;
OnContextCreated();
}
This will by default, get the connection string from your configuration file.
What you could do in this case is set the connection string
public partial class MyEntities
{
partial void OnContextCreated()
{
//Dynamically Building a Connection String
this.Connection.ConnectionString = "myconnectionstring";
}
}
Bear in mind though that this will first use the base constructor to pull the connection string from config, then set it with your custom version, basically overriding the connection string. This is typically good when you always want a default connection string.
Another option if you want a bit more control, is pass the connection string in via the constructor as shown below:
public partial class MyEntities
{
public MyEntities(string connectionString) :
base(connectionString,"MyEntities")
{
this.OnContextCreated();
}
}
Now you are passing in the connection string down to the base class and this is the only one it will use. This does mean however that you will most often need to supply this each time.
Hope this helps...

Related

Specify connection string for a query with DbContextScope project

I am currently using Mehdi El Gueddari's DbContextScope project, I think by the book, and it's awesome. But I came across a problem I'm unsure how to solve today. I have a query that I need to execute using a different database login/user because it requires additional permissions. I can create another connection string in my web.config, but I'm not sure how to specify that for this query, I want to use this new connection string. Here is my usage:
In my logic layer:
private static IDbContextScopeFactory _dbContextFactory = new DbContextScopeFactory();
public static Guid GetFacilityID(string altID)
{
...
using (_dbContextFactory.CreateReadOnly())
{
entity = entities.GetFacilityID(altID)
}
}
That calls into my data layer which would look something like this:
private AmbientDbContextLocator _dbcLocator = new AmbientDbContextLocator();
protected CRMEntities DBContext
{
get
{
var dbContext = _dbcLocator.Get<CRMEntities>();
if (dbContext == null)
throw new InvalidOperationException("No ambient DbContext....");
return dbContext;
}
}
public virtual Guid GetFaciltyID(string altID)
{
return DBContext.Set<Facility>().Where(f => f.altID = altID).Select(f => f.ID).FirstOrDefault();
}
Currently my connection string is set in the default way:
public partial class CRMEntities : DbContext
{
public CRMEntities()
: base("name=CRMEntities")
{}
}
Is it possible for this specific query to use a different connection string and how?
I ended up modifying the source code in a way that feels slightly hacky, but is getting the job done for now. I created a new IAmbientDbContextLocator with a Get<TDbContext> method override that accepts a connection string:
public TDbContext Get<TDbContext>(string nameOrConnectionString) where TDbContext : DbContext
{
var ambientDbContextScope = DbContextScope.GetAmbientScope();
return ambientDbContextScope == null ? null : ambientDbContextScope.DbContexts.Get<TDbContext>(nameOrConnectionString);
}
Then I updated the DbContextCollection to pass this parameter to the DbContext's existing constructor overload. Last, I updated the DbContextCollection maintain a Dictionary<KeyValuePair<Type, string>, DbContext> instead of a Dictionary<Type, DbContext> as its cached _initializedDbContexts where the added string is the nameOrConnectionString param. So in other words, I updated it to cache unique DbContext type/connection string pairs.
Then I can get at the DbContext with the connection I need like this:
var dbContext = new CustomAmbientDbContextLocator().Get<CRMEntities>("name=CRMEntitiesAdmin");
Of course you'd have to be careful your code doesn't end up going through two different contexts/connection strings when it should be going through the same one. In my case I have them separated into two different data access class implementations.

Entity Framework: DbContext and setting the ProviderName

When you derive from DbContext and use the parameter-less constructor it will load a connection string from web.config. You also have the option of explicitly specifying the connectionString using one of the other DbContext constructors.
My particular situation dictates that the connection string CANNOT be specified in the web.config, as the location of the server/username and password are determined at runtime. Easy fix right? Just use the above mentioned constructor to specify the connection string? Wrong.
The problem is that when you specify the connection string using said constructor, it still attempts to use the default provider, so if you're using one or more non standard providers, as I am, it will not work.
I'm sure I can change the default provider in the web.config, but I want to use multiple providers so this will not do.
The only possible way around this that I can see is to use ObjectContext instead of DbContext, which seems to allow you to specify the provider along with the database connection string.
Is there any other way to do it? Is my workaround fairly reasonable?
I believe I can also create a DbContext from an ObjectContext instance.
Create your DbConnection manually and pass it to the DbContext constructor as follows:
var conn = DbProviderFactories.GetFactory("MY_CONN_PROVIDER").CreateConnection();
conn.ConnectionString = "MY_CONN_STR";
new DbContext(conn, true);
Notice the second parameter bool contextOwnsConnection is true. Since you don't re-use the connection elsewhere, it lets the context manage the connection and Dispose() it when needed.
You can get to the ObjectContext through IObjectContextAdapter:
((IObjectContextAdapter)context).ObjectContext
DbContext ("context" above) still wraps ObjectContext, so don't worry that you will have a new instance.
You can instantiate DbContext using this overload
public DbContext(ObjectContext objectContext, bool dbContextOwnsObjectContext) {}
for example:
public class YourDbContext : DbContext
{
public YourDbContext() : this(new YourObjectEntities(), dbContextOwnsObjectContext: true)
{}
}
Then you can set your connection string inside of YourObjectEntities:
public partial class YourObjectEntities : ObjectContext
{
public const string ConnectionString = "name=YourEntities"; // Get it from somewhere
public YourObjectEntities() : base(ConnectionString, "YourEntities")
{
// Some initialization, e.g. ContextOptions.LazyLoadingEnabled = false;
}
}
How you specify the provider there is your exercise.
Try like this ,
public DBDataContext _dataContex;
public DBDataContext DBContext
{
get
{
if (_dataContex== null)
{
_v= new DBDataContext(ConfigurationManager.ConnectionStrings["yourConnectinString"].ConnectionString);
}
return _dataContex;
}
}

Use GuidRepresentation.Standard with MongoDB

I am implementing a custom IBsonSerializer with the official MongoDB driver (C#). I am in the situation where I must serialize and deserialize a Guid.
If I implement the Serialize method as follow, it works:
public void Serialize(BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options)
{
BsonBinaryData data = new BsonBinaryData(value, GuidRepresentation.CSharpLegacy);
bsonWriter.WriteBinaryData(data);
}
However I don't want the Guid representation to be CSharpLegacy, I want to use the standard representation. But if I change the Guid representation in that code, I get the following error:
MongoDB.Bson.BsonSerializationException: The GuidRepresentation for the writer is CSharpLegacy, which requires the subType argument to be UuidLegacy, not UuidStandard.
How do I serialize a Guid value using the standard representation?
Old question but in case someone finds it on google like I did...
Do this once:
BsonDefaults.GuidRepresentation = GuidRepresentation.Standard;
For example, in a Web Application/Web API, your Global.asax.cs file is best place to add it once
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
BsonDefaults.GuidRepresentation = GuidRepresentation.Standard;
//Other code...below
}
}
If you don't want to modify the global setting BsonDefaults.GuidRepresentation (and you shouldn't, because modifying globals is a bad pattern), you can specify the setting when you create your collection:
IMongoDatabase db = ???;
string collectionName = ???;
var collectionSettings = new MongoCollectionSettings {
GuidRepresentation = GuidRepresentation.Standard
};
var collection = db.GetCollection<BsonDocument>(collectionName, collectionSettings);
Then any GUIDs written to the collection will be in the standard format.
Note that when you read records from the database, you will get a System.FormatException if the GUID format in the database is different from the format in your collection settings.
It looks like what's happening is when you are not explicitly passing the GuidRepresentation to BsonBinaryData constructor, it defaults to passing GuidRepresentation.Unspecified and that ultimately maps to GuidRepresentation.Legacy (see this line in the source)
So you need to explicitly pass the guidRepresentation as a third argument to BsonBinaryData set to GuidRepresentation.Standard.
edit: As was later pointed out, you can set BsonDefaults.GuidRepresentation = GuidRepresentation.Standard if that's what you always want to use.

Entity Framework 3.5: change constructor of entities class

The default constructor in a generated Entity Framework Entities file is like this:
public ProjectEntities() : base("name=ProjectEntities", "ProjectEntities")
{
this.OnContextCreated();
}
I want to change it to:
public ProjectEntities() : base(UtilClass.GetEnvDependantConnectionStringName(), "ProjectEntities")
{
this.OnContextCreated();
}
This is because I want to have a different connection string for all the dev environments and the production environment, and have no chance they are mixed up (which is what my custom method checks).
How do I do that? This code is thrown away every time the designer file is regenerated.
You need to create another file alongside the auto-created ProjectEntities.Designer.cs, say ProjectEntities.cs. In that you use partial to extend the functionality of your entities class like this:
public partial class ProjectEntities : ObjectContext
{
partial void OnContextCreated()
{
this.Connection.ConnectionString = UtilClass.GetEnvDependantConnectionString();
}
}
The file won't then get changed when you regenerate the .Designer.cs file. You'll have to fetch the connection string yourself...
We fixed it by calling our entities ProjectEntitiesPrivate, and what was partial class ProjectEntities before, is now a non partial class ProjectEntities : ProjectEntitiesPrivate, with the constructor I need:
public class ProjectEntities: ProjectEntitiesPrivate
{
public ProjectEntities():base(UtilClass.GetEnvDependantConnectionStringName())
{
}
....

Single Connection String with Multiple Entity Framework Models?

At work we currently have a very large web application with a connection to a massive database. We have been using Entity Framework for a while now and to make things easier we divided the database into many Entity models. This works well for us but we ran into an issue. Each EF model needs its own connection string due to the metadata part of the connection string. Managing so many connection string is a pain.
Now I have a solution that I think will work. I am going to create a class that will have the metadata info saved as a property also concatenated to the standard connection string in the web.config. So when we use the connection string "Database.EntityConnectionString" it will give me the Entity Connection string but we only have to manage a single connection string in the web.config. We will still have to manage the class with the metadata but Models don't change very much and we don't create them often so maintenance should be fine. My question, is there a better way of dealing with this issue or how would you do it?
Thanks!
This is how I have implemented my solution to this problem:
namespace DBLibrary
{
public enum Models
{
Model1,
Model2
}
public static class Database
{
public static string EntitiesConnectionString(Models model)
{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(ConfigurationManager.ConnectionStrings["Default"].ConnectionString);
builder["MultipleActiveResultSets"] = true;
builder["Connect Timeout"] = 30;
EntityConnectionStringBuilder entityBuilder = new EntityConnectionStringBuilder();
entityBuilder.Provider = "System.Data.SqlClient";
entityBuilder.ProviderConnectionString = builder.ConnectionString;
switch (model)
{
case Models.Model1:
entityBuilder.Metadata = "res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl";
return entityBuilder.ToString();
case Models.Model2:
entityBuilder.Metadata = "res://*/Model2.csdl|res://*/Model2.ssdl|res://*/Model2.msl";
return entityBuilder.ToString();
default:
throw new Exception("Invalid model, no connection string defined");
}
}
}
}
I still need to clean up the code and all but I think this give you a good idea on how this can be implemented. I would still be very interested if there are different and better ways of doing this.
Thanks!
Add Default Construction in your Class
public class ItemContext : DbContext
{
public DbSet<Item>Items get; set; }
public DbSet<ItemDetail> ItemDetails { get; set; }
public ItemContext ()
{
this.Database.Connection.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
}
}
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="data source=abc;initial catalog=mydb;persist security info=True;user id=myuser;password=password;MultipleActiveResultSets=True;App=EntityFramework"" 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.