I have database connection setup with Entity Framework. I've created multiple stored procedures and one of them has an output parameter that I need in my application.
Procedure in c# :
public virtual ObjectResult<Nullable<System.Guid>> AjouterProfesseur(string prenom, string nom, ObjectParameter identity)
{
var prenomParameter = prenom != null ?
new ObjectParameter("prenom", prenom) :
new ObjectParameter("prenom", typeof(string));
var nomParameter = nom != null ?
new ObjectParameter("nom", nom) :
new ObjectParameter("nom", typeof(string));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<Nullable<System.Guid>>("AjouterProfesseur", prenomParameter, nomParameter, identity);
}
To retrieve the output parameter I use following (this is also where I have to put my breakpoint and step over it for it to work):
public static Guid AddProfesseur(string prenom, string nom)
{
using (ExamenProjetIntegrationEntities db = new ExamenProjetIntegrationEntities())
{
ObjectParameter objParam = new ObjectParameter("identity", typeof(Guid));
var resultToReturn = db.AjouterProfesseur(prenom, nom, objParam);
return Guid.Parse(objParam.Value.ToString());
}
}
Then I have a business layer who calls that method again :
public static Guid addProfesseur(string prenom, string nom)
{
try
{
var data = Data.AddProfesseur(prenom, nom);
return data;
}
catch (Exception e)
{
var sqlex = e.InnerException as SqlException;
if (sqlex != null)
{
switch (sqlex.Number)
{
default:
throw new Exception(sqlex.Number + " - " + sqlex.Message);
}
}
throw e;
}
}
And finally in my API controller I'm using following statement :
var idProfesseur = BL.addProfesseur(professeur.prenom, professeur.nom);
I call the method with ajax in my ASP.NET MVC view.
Does anyone has any idea why this is and how I can solve this issue?
EDIT :
Following link is exactly what I'm doing : Executing SQL Stored Procedure with Output Parameter from Entity Framework .But my problem is the fact that I need to step through it for it to work
Output parameters are not available until the return result has been read completely, or the underlying DbDataReader is closed.
See the Parameters section of ObjectContext.ExecuteFunction, and the second sentence of this section on DataReaders
You can force this by evaluating the result with LINQ.
public static Guid AddProfesseur(string prenom, string nom)
{
using (ExamenProjetIntegrationEntities db = new ExamenProjetIntegrationEntities())
{
ObjectParameter objParam = new ObjectParameter("identity", typeof(Guid));
var resultToReturn = db.AjouterProfesseur(prenom, nom, objParam).Count();
return Guid.Parse(objParam.Value.ToString());
}
}
You could also use .ToList(), .FirstOrDefault(), or whatever method you prefer to read the underlying result.
Using the underlying SqlParameter would require .Direction = ParameterDirection.Output. ObjectParameter doesn't have an equivalent setting. Instead I believe the parameter direction is configured in your model.
I have developed an accounting program that is working beautifully, but now a new need has arisen.
When I enter the program, by default it reads the DB that I put in the file WinSCM.exe.config and if I want to change I have to exit the program and edit the file changing the DB name.
I did not want it to be this way, because my client does accounting for several companies and each company is a DB, so I wanted a way to select a company and when selecting this company the database is automatically changed in the release version.
I'm using Entity Framework to connect to Sql Server DB
Can someone help me?
I'm not sure what reading your DB is, but normally when you use Entity Framework you create a DbContext object whenever you need to do a query, or at utmost a few queries. You are not supposed to keep this DbContext alive for longer periods of time, say more than a few seconds. A minute would be very rare.
Whenever you create the Dbcontext instance you could use the default constructor that uses the config file to get the connection string to the database.
However one of the other constructors let you define the connection string to the database in the constructor. So if you want to construct your DbContext and connect it to a different database, just use that constructor
If you don't know the connection string, but you have a DbConnection to the database, there will be even a constructor for this case.
Hi Everybody Thank alot for your Answer. I just Solved My Question like this:
Fisrt of all, I created a class wich I called ConnetionTolls with this Content://.
public static class ConnectionTools
{
// all params are optional
public static void ChangeDatabase(
this DbContext source,
string initialCatalog = "",
string dataSource = "",
string userId = "",
string password = "",
bool integratedSecuity = true,
string configConnectionStringName = "")
/* this would be used if the
* connectionString name varied from
* the base EF class name */
{
try
{
// use the const name if it's not null, otherwise
// using the convention of connection string = EF contextname
// grab the type name and we're done
var configNameEf = string.IsNullOrEmpty(configConnectionStringName)
? source.GetType().Name
: configConnectionStringName;
// add a reference to System.Configuration
var entityCnxStringBuilder = new EntityConnectionStringBuilder
(System.Configuration.ConfigurationManager
.ConnectionStrings[configNameEf].ConnectionString);
// init the sqlbuilder with the full EF connectionstring cargo
var sqlCnxStringBuilder = new SqlConnectionStringBuilder
(entityCnxStringBuilder.ProviderConnectionString);
// only populate parameters with values if added
if (!string.IsNullOrEmpty(initialCatalog))
sqlCnxStringBuilder.InitialCatalog = initialCatalog;
if (!string.IsNullOrEmpty(dataSource))
sqlCnxStringBuilder.DataSource = dataSource;
if (!string.IsNullOrEmpty(userId))
sqlCnxStringBuilder.UserID = userId;
if (!string.IsNullOrEmpty(password))
sqlCnxStringBuilder.Password = password;
// set the integrated security status
sqlCnxStringBuilder.IntegratedSecurity = integratedSecuity;
// now flip the properties that were changed
source.Database.Connection.ConnectionString
= sqlCnxStringBuilder.ConnectionString;
}
catch (Exception ex)
{
// set log item if required
}
}
********the way to use it is like this***************
//I use this method in a diferent Class
//This method returns the Entity i use with new connections
public static MyEntities SelectDb(String DataBase,String sqlUser,String pw, String serverInstance){
var selectedDbase = new MyEntities();
// so only reference the changed properties
// using the object parameters by name
selectedDbase.ChangeDatabase
(
initialCatalog: DataBase,
userId: sqlUser,
password: pw,
dataSource: serverInstance// could be ip address 100.23.45.67 etc
);
return selectedDbase;
}
I want to thank everyone here and on other forums because this was the result of Your Contributions
I've built my project and named the db connection "VMaxEntities"
The connection string exists in web.config.
I have another connection string "Development_VMaxEntities"
Whenever I call the db, I use the code using (VMaxEntities db = new VMaxEntities())
This calls:
public partial class VMaxEntities : DbContext
{
public VMaxEntities()
: base("name=VMaxEntities")
{
}
What I want to do is connect to a development database instead of the live one, IF the current URI contains localhost.
So - thanks to cgotberg's answer below, here's what I used to get it working: (note, I add the password here instead of in web.config)
public VMaxEntities()
: base("name=Secure_VMaxEntities")
{
if (System.Web.HttpContext.Current.Request.Url.Host == "localhost")
{
var connectionString = this.Database.Connection.ConnectionString + ";password=***********";
this.Database.Connection.ConnectionString = connectionString.Replace("catalog=VMax", "catalog=DEV_VMax");
}
else
{
this.Database.Connection.ConnectionString += ";password=************";
}
}
I've done something like this in the past
using(var db = new VMaxEntities())
{
var connectionString = context.Database.Connection.ConnectionString;
var datasource = context.Database.Connection.DataSource;
var databaseServer = "yourDevDatabaseServerName"
db.Database.Connection.ConnectionString = connectionString.Replace(datasource, databaseServer);
}
I have a web API project which references my model and DAL assemblies. The user is presented with a login screen, where he can select different databases.
I build the connection string as follows:
public void Connect(Database database)
{
//Build an SQL connection string
SqlConnectionStringBuilder sqlString = new SqlConnectionStringBuilder()
{
DataSource = database.Server,
InitialCatalog = database.Catalog,
UserID = database.Username,
Password = database.Password,
};
//Build an entity framework connection string
EntityConnectionStringBuilder entityString = new EntityConnectionStringBuilder()
{
Provider = database.Provider,
Metadata = Settings.Default.Metadata,
ProviderConnectionString = sqlString.ToString()
};
}
First of all, how do I actually change the connection of the data context?
And secondly, as this is a web API project, is the connection string (set at login per above) persistent throughout the user's interaction or should it be passed every time to my data context?
A bit late on this answer but I think there's a potential way to do this with a neat little extension method. We can take advantage of the EF convention over configuration plus a few little framework calls.
Anyway, the commented code and example usage:
extension method class:
public static class ConnectionTools
{
// all params are optional
public static void ChangeDatabase(
this DbContext source,
string initialCatalog = "",
string dataSource = "",
string userId = "",
string password = "",
bool integratedSecuity = true,
string configConnectionStringName = "")
/* this would be used if the
* connectionString name varied from
* the base EF class name */
{
try
{
// use the const name if it's not null, otherwise
// using the convention of connection string = EF contextname
// grab the type name and we're done
var configNameEf = string.IsNullOrEmpty(configConnectionStringName)
? source.GetType().Name
: configConnectionStringName;
// add a reference to System.Configuration
var entityCnxStringBuilder = new EntityConnectionStringBuilder
(System.Configuration.ConfigurationManager
.ConnectionStrings[configNameEf].ConnectionString);
// init the sqlbuilder with the full EF connectionstring cargo
var sqlCnxStringBuilder = new SqlConnectionStringBuilder
(entityCnxStringBuilder.ProviderConnectionString);
// only populate parameters with values if added
if (!string.IsNullOrEmpty(initialCatalog))
sqlCnxStringBuilder.InitialCatalog = initialCatalog;
if (!string.IsNullOrEmpty(dataSource))
sqlCnxStringBuilder.DataSource = dataSource;
if (!string.IsNullOrEmpty(userId))
sqlCnxStringBuilder.UserID = userId;
if (!string.IsNullOrEmpty(password))
sqlCnxStringBuilder.Password = password;
// set the integrated security status
sqlCnxStringBuilder.IntegratedSecurity = integratedSecuity;
// now flip the properties that were changed
source.Database.Connection.ConnectionString
= sqlCnxStringBuilder.ConnectionString;
}
catch (Exception ex)
{
// set log item if required
}
}
}
basic usage:
// assumes a connectionString name in .config of MyDbEntities
var selectedDb = new MyDbEntities();
// so only reference the changed properties
// using the object parameters by name
selectedDb.ChangeDatabase
(
initialCatalog: "name-of-another-initialcatalog",
userId: "jackthelady",
password: "nomoresecrets",
dataSource: #".\sqlexpress" // could be ip address 120.273.435.167 etc
);
I know you already have the basic functionality in place, but thought this would add a little diversity.
DbContext has a constructor overload that accepts the name of a connection string or a connection string itself. Implement your own version and pass it to the base constructor:
public class MyDbContext : DbContext
{
public MyDbContext( string nameOrConnectionString )
: base( nameOrConnectionString )
{
}
}
Then simply pass the name of a configured connection string or a connection string itself when you instantiate your DbContext
var context = new MyDbContext( "..." );
Jim Tollan's answer works great, but I got the Error: Keyword not supported 'data source'.
To solve this problem I had to change this part of his code:
// add a reference to System.Configuration
var entityCnxStringBuilder = new EntityConnectionStringBuilder
(System.Configuration.ConfigurationManager
.ConnectionStrings[configNameEf].ConnectionString);
to this:
// add a reference to System.Configuration
var entityCnxStringBuilder = new EntityConnectionStringBuilder
{
ProviderConnectionString = new SqlConnectionStringBuilder(System.Configuration.ConfigurationManager
.ConnectionStrings[configNameEf].ConnectionString).ConnectionString
};
I'm really sorry. I know that I should't use answers to respond to other answers, but my answer is too long for a comment :(
The created class is 'partial'!
public partial class Database1Entities1 : DbContext
{
public Database1Entities1()
: base("name=Database1Entities1")
{
}
... and you call it like this:
using (var ctx = new Database1Entities1())
{
#if DEBUG
ctx.Database.Log = Console.Write;
#endif
so, you need only create a partial own class file for original auto-generated class (with same class name!) and add a new constructor with connection string parameter, like Moho's answer before.
After it you able to use parametrized constructor against original. :-)
example:
using (var ctx = new Database1Entities1(myOwnConnectionString))
{
#if DEBUG
ctx.Database.Log = Console.Write;
#endif
You can do this on-the-fly with an IDbConnectionInterceptor. This has the advantage of allowing you to work with a standard connection string and not the Entity Client version, and also not having to modify the auto-generated context classes in an EDMX model, or using overloaded constructors. It just works!
We use this, for instance, to replace a tokenized connection string with a password from a secrets vault.
First, implement the interface. I'm only showing one of the many interface methods that will need to be implemented. In this case, I'm implementing ConnectionStringGetting, and leaving all other method bodies empty:
public class SecretsDbConnectionInterceptor : IDbConnectionInterceptor
{
public void ConnectionStringGetting(DbConnection connection, DbConnectionInterceptionContext<string> interceptionContext)
{
var originalConnectionString = connection.ConnectionString;
try
{
connection.ConnectionString = /* Build your new connection string */;
}
catch (Exception e)
{
connection.ConnectionString = originalConnectionString;
Trace.WriteLine(e.Message);
}
}
// ... Many other methods here; leave them empty
}
You can wire this up via your .config file; just add an <interceptor /> to the existing <entityFramework /> node with your new inteceptor's fully qualified type name:
<entityFramework>
<interceptors>
<interceptor type="Foo.Bar.SecretsDbConnectionInterceptor, Foo.Bar" />
</interceptors>
...
</entityFramework>
Or, my personal preference, you can wire it up via code. It is equivalent to the config version. Ideally this would go in an Application_Startup in a service/UI project, or towards the top of Main in a console app, because it must run before you attempt to establish any new DbContexts:
DbInterception.Add(new Foo.Bar.SecretsDbConnectionInterceptor());
When you configure via code, you could pass parameters to your interceptor constructor, or use DI.
Note: the interceptor code runs every time you create a new instance of any DbContext in your application, so beware of performance impacts. You could implement some caching strategy within your interceptor, or make it a singleton instance with a context name/connection string mapping, or something smart like that.
Add multiple connection strings in your web.config or app.config.
Then you can get them as a string like :
System.Configuration.ConfigurationManager.
ConnectionStrings["entityFrameworkConnection"].ConnectionString;
Then use the string to set :
Provider
Metadata
ProviderConnectionString
It is better explained here :
Read connection string from web.config
string _connString = "metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl;provider=System.Data.SqlClient;provider connection string="data source=localhost;initial catalog=DATABASE;persist security info=True;user id=sa;password=YourPassword;multipleactiveresultsets=True;App=EntityFramework"";
EntityConnectionStringBuilder ecsb = new EntityConnectionStringBuilder(_connString);
ctx = new Entities(_connString);
You can get the connection string from the web.config, and just set that in the EntityConnectionStringBuilder constructor, and use the EntityConnectionStringBuilder as an argument in the constructor for the context.
Cache the connection string by username. Simple example using a couple of generic methods to handle adding/retrieving from cache.
private static readonly ObjectCache cache = MemoryCache.Default;
// add to cache
AddToCache<string>(username, value);
// get from cache
string value = GetFromCache<string>(username);
if (value != null)
{
// got item, do something with it.
}
else
{
// item does not exist in cache.
}
public void AddToCache<T>(string token, T item)
{
cache.Add(token, item, DateTime.Now.AddMinutes(1));
}
public T GetFromCache<T>(string cacheKey) where T : class
{
try
{
return (T)cache[cacheKey];
}
catch
{
return null;
}
}
In my case I'm using the ObjectContext as opposed to the DbContext so I tweaked the code in the accepted answer for that purpose.
public static class ConnectionTools
{
public static void ChangeDatabase(
this ObjectContext source,
string initialCatalog = "",
string dataSource = "",
string userId = "",
string password = "",
bool integratedSecuity = true,
string configConnectionStringName = "")
{
try
{
// use the const name if it's not null, otherwise
// using the convention of connection string = EF contextname
// grab the type name and we're done
var configNameEf = string.IsNullOrEmpty(configConnectionStringName)
? Source.GetType().Name
: configConnectionStringName;
// add a reference to System.Configuration
var entityCnxStringBuilder = new EntityConnectionStringBuilder
(System.Configuration.ConfigurationManager
.ConnectionStrings[configNameEf].ConnectionString);
// init the sqlbuilder with the full EF connectionstring cargo
var sqlCnxStringBuilder = new SqlConnectionStringBuilder
(entityCnxStringBuilder.ProviderConnectionString);
// only populate parameters with values if added
if (!string.IsNullOrEmpty(initialCatalog))
sqlCnxStringBuilder.InitialCatalog = initialCatalog;
if (!string.IsNullOrEmpty(dataSource))
sqlCnxStringBuilder.DataSource = dataSource;
if (!string.IsNullOrEmpty(userId))
sqlCnxStringBuilder.UserID = userId;
if (!string.IsNullOrEmpty(password))
sqlCnxStringBuilder.Password = password;
// set the integrated security status
sqlCnxStringBuilder.IntegratedSecurity = integratedSecuity;
// now flip the properties that were changed
source.Connection.ConnectionString
= sqlCnxStringBuilder.ConnectionString;
}
catch (Exception ex)
{
// set log item if required
}
}
}
I wanted to have multiple datasources in the app config. So after setting up a section in the app.config i swaped out the datasource and then pass it into the dbcontext as the connection string.
//Get the key/value connection string from app config
var sect = (NameValueCollection)ConfigurationManager.GetSection("section");
var val = sect["New DataSource"].ToString();
//Get the original connection string with the full payload
var entityCnxStringBuilder = new EntityConnectionStringBuilder(ConfigurationManager.ConnectionStrings["OriginalStringBuiltByADO.Net"].ConnectionString);
//Swap out the provider specific connection string
entityCnxStringBuilder.ProviderConnectionString = val;
//Return the payload with the change in connection string.
return entityCnxStringBuilder.ConnectionString;
This took me a bit to figure out. I hope it helps someone out. I was making it way too complicated. before this.
I have two extension methods to convert the normal connection string to the Entity Framework format. This version working well with class library projects without copying the connection strings from app.config file to the primary project. This is VB.Net but easy to convert to C#.
Public Module Extensions
<Extension>
Public Function ToEntityConnectionString(ByRef sqlClientConnStr As String, ByVal modelFileName As String, Optional ByVal multipleActiceResultSet As Boolean = True)
Dim sqlb As New SqlConnectionStringBuilder(sqlClientConnStr)
Return ToEntityConnectionString(sqlb, modelFileName, multipleActiceResultSet)
End Function
<Extension>
Public Function ToEntityConnectionString(ByRef sqlClientConnStrBldr As SqlConnectionStringBuilder, ByVal modelFileName As String, Optional ByVal multipleActiceResultSet As Boolean = True)
sqlClientConnStrBldr.MultipleActiveResultSets = multipleActiceResultSet
sqlClientConnStrBldr.ApplicationName = "EntityFramework"
Dim metaData As String = "metadata=res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl;provider=System.Data.SqlClient;provider connection string='{1}'"
Return String.Format(metaData, modelFileName, sqlClientConnStrBldr.ConnectionString)
End Function
End Module
After that I create a partial class for DbContext:
Partial Public Class DlmsDataContext
Public Shared Property ModelFileName As String = "AvrEntities" ' (AvrEntities.edmx)
Public Sub New(ByVal avrConnectionString As String)
MyBase.New(CStr(avrConnectionString.ToEntityConnectionString(ModelFileName, True)))
End Sub
End Class
Creating a query:
Dim newConnectionString As String = "Data Source=.\SQLEXPRESS;Initial Catalog=DB;Persist Security Info=True;User ID=sa;Password=pass"
Using ctx As New DlmsDataContext(newConnectionString)
' ...
ctx.SaveChanges()
End Using
For both SQL Server and SQLite Databases, use:
_sqlServerDBsContext = new SqlServerDBsContext(new DbContextOptionsBuilder<SqlServerDBsContext>().UseSqlServer("Connection String to SQL DB").Options);
For SQLite, make sure Microsoft.EntityFrameworkCore.Sqlite is
installed, then the connection string is simply "'DataSource='+ the file name".
_sqliteDBsContext = new SqliteDBsContext(new DbContextOptionsBuilder<SqliteDBsContext>().UseSqlite("Connection String to SQLite DB").Options);
well if you are working with EFCore, Then You can do something like to create a new connection string:
In Your Context File (For Sqlite)
public biorevContext(string connectionString) : base(GetOptions(connectionString))
{
this.Database.EnsureCreated();
}
private static DbContextOptions GetOptions(string connectionString)
{
return SqliteDbContextOptionsBuilderExtensions.UseSqlite(new DbContextOptionsBuilder(), connectionString).Options;
}
For MySql:
public biorevContext(string connectionString) : base(GetOptions(connectionString))
{
this.Database.EnsureCreated();
}
private static DbContextOptions GetOptions(string connectionString)
{
return MySQLDbContextOptionsExtensions.UseMySQL(new DbContextOptionsBuilder(), connectionString).Options;
}
For Sql:
public biorevContext(string connectionString) : base(GetOptions(connectionString))
{
this.Database.EnsureCreated();
}
private static DbContextOptions GetOptions(string connectionString)
{
return SqlServerDbContextOptionsExtensions.UseSqlServer(new DbContextOptionsBuilder(), connectionString).Options;
}
and Then You can use it like this:
var context = new biorevContext("connectionString");
Linq2SQLDataClassesDataContext db = new Linq2SQLDataClassesDataContext();
var query = from p in db.SyncAudits orderby p.SyncTime descending select p;
Console.WriteLine(query.ToString());
try this code...
I´ve searched for some topics, but did not find a concrete solution to my problem.
My app is a c# commercial app. I´m using EF 4.1 database first. I generate the model from a development database connection and that create a Model.edmx file and all EF stuff pretty fine.
My goal is to deliver an appplication to the customer and let him freely create the database and database user at his own. Do do it, at runtime I would get the username, password, database connection and schema name parameters to connect to customer database. In that way, to deploy the application all I need is to ask the customer to create a database and add the database parameters to the app config file.
So, myy goal is to change the connection string and schema parameter at runtime, without changing att all the auto generated edmx file, not touching the VS generated code.
I have looked around and found:
For EF earlier versions:
Changing schema name on runtime - Entity Framework
http://efmodeladapter.codeplex.com
All other posts are going around that. I tryed even to use the first post code with no success.
But I´ve seen that EF 4.1 comes with better support tools to do it, but I could not find references or examples to it. It´s important not to change the auto generated code from VS.
I´m pretty new to EF, so I would like to ask for help on accomplish the following tasks:
a) Change connection string at runtime adding my username, password and database server/port parameters
b) Change database schema
I´m using Oracle as a database server (that makes things worst as Oracle mixes schema and users together).
Actually, I needed solution for this too. I quickly whipped up solution, which works nicely. I didn't find much information about this in Internet, so I am not sure about the "EF 4.1 comes with better support tools to do it".
The concrete example "Changing schema name on runtime - Entity framework" didn't entirely work for me, however with some minor modifications I got it working.
Here is a DatabaseUtils class that can do it:
internal static class DatabaseUtils
{
/// <summary>
/// Builds the connection string for Entity framework.
/// </summary>
/// <returns></returns>
public static EntityConnection BuildConnection(BuildConnectionParams buildConnectionParams)
{
var sqlBuilder = new SqlConnectionStringBuilder
{
DataSource = buildConnectionParams.ServerName,
InitialCatalog = buildConnectionParams.DatabaseName,
IntegratedSecurity = true
};
var providerString = sqlBuilder.ToString();
var entityBuilder = new EntityConnectionStringBuilder
{
Provider = buildConnectionParams.ProviderName,
ProviderConnectionString = providerString,
Metadata = string.Format(#"res://*/{0}.csdl|
res://*/{0}.ssdl|
res://*/{0}.msl", buildConnectionParams.ModelName)
};
return CreateConnection(buildConnectionParams.SchemaName, entityBuilder, buildConnectionParams.ModelName);
}
/// <summary>
/// Creates the EntityConnection, based on new schema & existing connectionString
/// </summary>
/// <param name="schemaName">Name of the schema.</param>
/// <param name="connectionBuilder"></param>
/// <param name="modelName">Name of the model.</param>
/// <returns></returns>
private static EntityConnection CreateConnection(string schemaName, EntityConnectionStringBuilder connectionBuilder, string modelName)
{
Func<string, Stream> generateStream =
extension => Assembly.GetExecutingAssembly().GetManifestResourceStream(string.Concat(modelName, extension));
Action<IEnumerable<Stream>> disposeCollection = streams =>
{
if (streams == null)
return;
foreach (var stream in streams.Where(stream => stream != null))
stream.Dispose();
};
var conceptualReader = generateStream(".csdl");
var mappingReader = generateStream(".msl");
var storageReader = generateStream(".ssdl");
if (conceptualReader == null || mappingReader == null || storageReader == null)
{
disposeCollection(new[] { conceptualReader, mappingReader, storageReader });
return null;
}
var storageXml = XElement.Load(storageReader);
foreach (var entitySet in storageXml.Descendants())
{
var schemaAttribute = entitySet.Attributes("Schema").FirstOrDefault();
if (schemaAttribute != null)
schemaAttribute.SetValue(schemaName);
}
storageXml.CreateReader();
var workspace = new MetadataWorkspace();
var storageCollection = new StoreItemCollection(new[] { storageXml.CreateReader() });
var conceptualCollection = new EdmItemCollection(new[] { XmlReader.Create(conceptualReader) });
var mappingCollection = new StorageMappingItemCollection(conceptualCollection,
storageCollection,
new[] { XmlReader.Create(mappingReader) });
workspace.RegisterItemCollection(conceptualCollection);
workspace.RegisterItemCollection(storageCollection);
workspace.RegisterItemCollection(mappingCollection);
var connection = DbProviderFactories.GetFactory(connectionBuilder.Provider).CreateConnection();
if (connection == null)
{
disposeCollection(new[] { conceptualReader, mappingReader, storageReader });
return null;
}
connection.ConnectionString = connectionBuilder.ProviderConnectionString;
return new EntityConnection(workspace, connection);
}
}
Usage:
/// <summary>
/// Initializes a new instance of the <see cref="DynamicAQDContext"/> class.
/// </summary>
public DynamicAQDContext()
{
var entityConnection = DatabaseUtils.BuildConnection(new BuildConnectionParams
{
ProviderName = "System.Data.SqlClient",
ServerName = "localhost\\",
DatabaseName = "",
ModelName = "YOURMODEL",
SchemaName = "SCHEMA"
});
if(entityConnection == null)
throw new Exception("Can't create EntityConnection");
_entities = new LINKEntities(entityConnection);
}
more info can be found here: http://bestplayah.com/entity-framework-dynamic-schema-changes-using-database-first-approach/