Connexion de changement de cadre d'entité à l'exécution

j'ai un projet D'API web qui fait référence à mon modèle et à mes assemblages DAL. L'utilisateur est présenté avec un écran de connexion, où il peut sélectionner différentes bases de données.

je construis la chaîne de connexion comme suit:

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

tout d'abord, comment changer la connexion du contexte de données?

et deuxièmement, comme il s'agit d'un projet D'API web, est la chaîne de connexion (définie à login per ci-dessus) persistante tout au long l'utilisateur de l'interaction, ou doit-elle être transmise à chaque fois à mes données?

64
demandé sur gorkem 2013-11-26 15:42:33

10 réponses

un peu en retard sur cette réponse, mais je pense qu'il ya un moyen potentiel de le faire avec une petite extension méthode. Nous pouvons tirer profit de la convention EF plutôt que de la configuration, en plus de quelques appels-cadres.

en tout cas, le code commenté et l'exemple d'usage:

classe de la méthode d'extension:

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

usage de base:

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

je sais que vous avez déjà la fonctionnalité de base dans mais j'ai pensé que cela ajouterait un peu de diversité.

95
répondu jim tollan 2013-11-27 22:42:50

DbContext a une surcharge du constructeur qui accepte le nom d'une chaîne de connexion ou une chaîne de connexion elle-même. Implémentez votre propre version et passez-la au constructeur de base:

public class MyDbContext : DbContext
{
    public MyDbContext( string nameOrConnectionString ) 
        : base( nameOrConnectionString )
    {
    }
}

alors passez simplement le nom d'une chaîne de connexion configurée ou une chaîne de connexion elle-même lorsque vous instanciez votre DbContext

var context = new MyDbContext( "..." );
52
répondu Moho 2013-11-26 12:49:45

Jim Tollan réponse fonctionne très bien, mais j'ai l'Erreur: le mot-Clé pas supporté "source de données". Pour résoudre ce problème j'ai dû changer cette partie de son code:

// add a reference to System.Configuration
var entityCnxStringBuilder = new EntityConnectionStringBuilder
    (System.Configuration.ConfigurationManager
            .ConnectionStrings[configNameEf].ConnectionString);

à ceci:

// add a reference to System.Configuration
var entityCnxStringBuilder = new EntityConnectionStringBuilder
{
    ProviderConnectionString = new  SqlConnectionStringBuilder(System.Configuration.ConfigurationManager
               .ConnectionStrings[configNameEf].ConnectionString).ConnectionString
};

je suis vraiment désolé. Je sais que je ne devrais pas utiliser les réponses pour répondre à d'autres réponses, mais ma réponse est trop longue pour un commentaire : (

10
répondu A.Ima 2017-01-30 15:24:35

La classe créée est "partielle"!

public partial class Database1Entities1 : DbContext
{
    public Database1Entities1()
        : base("name=Database1Entities1")
    {
    }

... et vous appelez ça comme ça:

using (var ctx = new Database1Entities1())
      {
        #if DEBUG
        ctx.Database.Log = Console.Write;
        #endif

donc, vous n'avez besoin de créer qu'une partie propre fichier de classe pour la classe d'origine générée automatiquement (avec le même nom de classe!) et Ajouter un nouveau constructeur avec le paramètre connection string, comme la réponse de Moho avant.

après cela, vous pouvez utiliser le constructeur paramétré contre original. :- )

exemple:

using (var ctx = new Database1Entities1(myOwnConnectionString))
      {
        #if DEBUG
        ctx.Database.Log = Console.Write;
        #endif
6
répondu eMeL 2014-02-20 20:31:04

ajouter plusieurs chaînes de connexion dans votre web.config ou app.config.

alors vous pouvez les obtenir comme une chaîne comme:

System.Configuration.ConfigurationManager.
    ConnectionStrings["entityFrameworkConnection"].ConnectionString;

ensuite, utilisez la chaîne de caractères pour définir :

Provider
Metadata
ProviderConnectionString

il est mieux expliqué ici :

lire chaîne de connexion du web.config

0
répondu Bryan Arbelo 2017-05-23 12:26:23
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);

Vous pouvez obtenir la chaîne de connexion à partir du web.config, et seulement ensemble que dans le EntityConnectionStringBuilder constructeur, et d'utiliser le EntityConnectionStringBuilder comme un argument dans le constructeur pour le contexte.

Cache la chaîne de connexion par nom d'utilisateur. Exemple Simple utilisant quelques méthodes génériques pour gérer l'ajout / la récupération du 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;
        }
    }
0
répondu scheien 2013-11-26 12:43:19

dans mon cas, j'utilise L'ObjectContext plutôt que le DbContext, donc j'ai modifié le code dans la réponse acceptée à cette fin.

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
        }
    }
}
0
répondu David 2014-08-12 22:38:33

je voulais avoir plusieurs sources de données dans la configuration de l'application. Donc, après avoir mis en place une section dans l'application.config je swaped la source de données, puis la passer dans la dbcontext que la chaîne de connexion.

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

ça m'a pris un peu de temps à comprendre. J'espère que cela aide quelqu'un. Je faisais ça trop compliqué. avant cette.

0
répondu Jake Porter 2016-12-14 19:07:59

j'ai deux méthodes d'extension pour convertir la chaîne de connexion normale au format Entity Framework. Cette version fonctionne bien avec les projets de bibliothèque de classe sans copier les chaînes de connexion de l'application.fichier de configuration pour le projet principal. C'est VB.Net mais facile à convertir en 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

après cela je crée une classe partielle pour 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

création d'une requête:

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
0
répondu SZL 2017-05-04 07:23:16
Linq2SQLDataClassesDataContext db = new Linq2SQLDataClassesDataContext();

var query = from p in db.SyncAudits orderby p.SyncTime descending select p;
Console.WriteLine(query.ToString());

essayez ce code...

-4
répondu saad mehmood khan 2015-07-23 08:20:59