web-dev-qa-db-fra.com

Chaînes de connexion pour Entity Framework

Je souhaite partager les mêmes informations de base de données entre plusieurs entités dans Silverlight .. mais je veux que la chaîne de connexion soit nommée xyz et que tout le monde accède à cette chaîne de connexion à partir de machine.config ...

La partie métadonnées des entités sera différente car je n'ai pas nommé les entités de la même façon.

Puis-je mettre plusieurs entités dans cette section de métadonnées?

Voici un exemple .. Je veux utiliser cette chaîne de connexion mais notez que j'ai mis plusieurs entités dans la section métadonnées ..

Fondamentalement, je veux prendre cette chaîne de connexion

<add name="XYZ" connectionString="metadata=res://*/ModEntity.csdl|res://*/ModEntity.ssdl|res://*/ModEntity.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=SomeServer;Initial Catalog=SomeCatalog;Persist Security Info=True;User ID=Entity;Password=SomePassword;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />

Et cette chaîne de connexion

 <add name="XYZ" connectionString="metadata=res://*/Entity.csdl|res://*/Entity.ssdl|res://*/Entity.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=SOMESERVER;Initial Catalog=SOMECATALOG;Persist Security Info=True;User ID=Entity;Password=Entity;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />

Pour créer cette chaîne de connexion

<add name="XYZ" connectionString="metadata=res://*/Entity.csdl|res://*/Entity.ssdl|res://*/Entity.msl|res://*/ModEntity.csdl|res://*/ModEntity.ssdl|res://*/ModEntity.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=SOMESERVER;Initial Catalog=SOMECATALOG;Persist Security Info=True;User ID=Entity;Password=SOMEPASSWORD;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />

Mais cela ne fonctionne tout simplement pas. Aucun des deux projets ne peut s'y connecter.

string encConnection = ConfigurationManager.ConnectionStrings[connectionName].ConnectionString;
Type contextType = typeof(test_Entities);
object objContext = Activator.CreateInstance(contextType, encConnection);
return objContext as test_Entities; 
27
Rico

Malheureusement, la combinaison de plusieurs contextes d'entité en une seule connexion nommée n'est pas possible. Si vous souhaitez utiliser des chaînes de connexion nommées à partir d'un fichier .config pour définir vos connexions Entity Framework, elles devront chacune avoir un nom différent. Par convention, ce nom est généralement le nom du contexte:

<add name="ModEntity" connectionString="metadata=res://*/ModEntity.csdl|res://*/ModEntity.ssdl|res://*/ModEntity.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=SomeServer;Initial Catalog=SomeCatalog;Persist Security Info=True;User ID=Entity;Password=SomePassword;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />
<add name="Entity" connectionString="metadata=res://*/Entity.csdl|res://*/Entity.ssdl|res://*/Entity.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=SOMESERVER;Initial Catalog=SOMECATALOG;Persist Security Info=True;User ID=Entity;Password=Entity;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />

Cependant, si vous vous retrouvez avec des conflits d'espace de noms, vous pouvez utiliser le nom de votre choix et simplement passer le nom correct au contexte lors de sa génération:

var context = new Entity("EntityV2");

Évidemment, cette stratégie fonctionne mieux si vous utilisez une injection d'usine ou de dépendance pour produire vos contextes.

Une autre option serait de produire la chaîne de connexion entière de chaque contexte par programme, puis de passer toute la chaîne au constructeur (pas seulement le nom).

// Get "Data Source=SomeServer..."
var innerConnectionString = GetInnerConnectionStringFromMachinConfig();
// Build the Entity Framework connection string.
var connectionString = CreateEntityConnectionString("Entity", innerConnectionString);
var context = new EntityContext(connectionString);

Que diriez-vous quelque chose comme ça:

Type contextType = typeof(test_Entities);
string innerConnectionString = ConfigurationManager.ConnectionStrings["Inner"].ConnectionString;
string entConnection = 
    string.Format(
        "metadata=res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl;provider=System.Data.SqlClient;provider connection string=\"{1}\"",
        contextType.Name,
        innerConnectionString);
object objContext = Activator.CreateInstance(contextType, entConnection);
return objContext as test_Entities; 

... avec les éléments suivants dans votre machine.config:

<add name="Inner" connectionString="Data Source=SomeServer;Initial Catalog=SomeCatalog;Persist Security Info=True;User ID=Entity;Password=SomePassword;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />

De cette façon, vous pouvez utiliser une chaîne de connexion unique pour chaque contexte dans chaque projet sur la machine.

41
StriplingWarrior

Au lieu d'utiliser des fichiers de configuration, vous pouvez utiliser une base de données de configuration avec une table systemConfig étendue et y ajouter tous vos paramètres.

CREATE TABLE [dbo].[SystemConfig]  
    (  
      [Id] [int] IDENTITY(1, 1)  
                 NOT NULL ,  
      [AppName] [varchar](128) NULL ,  
      [ScopeName] [varchar](128) NOT NULL ,  
      [Key] [varchar](256) NOT NULL ,  
      [Value] [varchar](MAX) NOT NULL ,  
      CONSTRAINT [PK_SystemConfig_ID] PRIMARY KEY NONCLUSTERED ( [Id] ASC )  
        WITH ( PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,  
               IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,  
               ALLOW_PAGE_LOCKS = ON ) ON [PRIMARY]  
    )  
ON  [PRIMARY]  

GO  

SET ANSI_PADDING OFF  
GO  

ALTER TABLE [dbo].[SystemConfig] ADD  CONSTRAINT [DF_SystemConfig_ScopeName]  DEFAULT ('SystemConfig') FOR [ScopeName]  
GO 

Avec une telle table de configuration, vous pouvez créer des lignes comme celles-ci: enter image description here

Ensuite, à partir de votre dal (s) d'application enveloppant EF, vous pouvez facilement récupérer la configuration étendue.
Si vous n'utilisez pas de dal (s) et travaillez directement dans le câble avec EF, vous pouvez créer une entité à partir de la table SystemConfig et utiliser la valeur en fonction de l'application sur laquelle vous vous trouvez.

5
Michel Triana

Essayez d'abord de comprendre comment fonctionne la chaîne de connexion Entity Framework, vous aurez alors une idée de ce qui ne va pas.

  1. Vous avez deux modèles différents, Entity et ModEntity
  2. Cela signifie que vous avez deux contextes différents, chaque contexte a son propre modèle de stockage, modèle conceptuel et mappage entre les deux.
  3. Vous avez simplement combiné des chaînes, mais comment le contexte d'Entity saura-t-il qu'il doit récupérer entity.csdl et ModEntity récupérera modentity.csdl? Eh bien, quelqu'un pourrait écrire du code intelligent, mais je ne pense pas que ce soit le rôle principal de l'équipe de développement EF.
  4. Machine.config est également une mauvaise idée.
  5. Si les applications Web sont déplacées vers une machine différente, ou vers un environnement d'hébergement partagé ou à des fins de maintenance, cela peut entraîner des problèmes.
  6. Tout le monde pourra y accéder, vous le rendez peu sûr. Si quelqu'un peut déployer une application Web ou une application .NET sur le serveur, il obtient un accès complet à votre chaîne de connexion, y compris vos informations de mot de passe sensibles.

Une autre alternative est que vous pouvez créer votre propre constructeur pour votre contexte et passer votre propre chaîne de connexion et vous pouvez écrire une condition if, etc. pour charger les valeurs par défaut à partir de web.config

La meilleure chose à faire serait de laisser les chaînes de connexion telles quelles, de donner à votre pool d'applications une identité qui aura accès à votre serveur de base de données et de ne pas inclure le nom d'utilisateur et le mot de passe dans la chaîne de connexion.

3
Akash Kava

Pour permettre au même edmx d'accéder à plusieurs bases de données et fournisseurs de bases de données et vice versa, j'utilise la technique suivante:

1) Définissez un ConnectionManager:

public static class ConnectionManager
{
    public static string GetConnectionString(string modelName)
    {
        var resourceAssembly = Assembly.GetCallingAssembly();

        var resources = resourceAssembly.GetManifestResourceNames();

        if (!resources.Contains(modelName + ".csdl")
            || !resources.Contains(modelName + ".ssdl")
            || !resources.Contains(modelName + ".msl"))
        {
            throw new ApplicationException(
                    "Could not find connection resources required by Assembly: "
                    + System.Reflection.Assembly.GetCallingAssembly().FullName);
        }

        var provider = System.Configuration.ConfigurationManager.AppSettings.Get(
                        "MyModelUnitOfWorkProvider");

        var providerConnectionString = System.Configuration.ConfigurationManager.AppSettings.Get(
                        "MyModelUnitOfWorkConnectionString");

        string ssdlText;

        using (var ssdlInput = resourceAssembly.GetManifestResourceStream(modelName + ".ssdl"))
        {
            using (var textReader = new StreamReader(ssdlInput))
            {
                ssdlText = textReader.ReadToEnd();
            }
        }

        var token = "Provider=\"";
        var start = ssdlText.IndexOf(token);
        var end = ssdlText.IndexOf('"', start + token.Length);
        var oldProvider = ssdlText.Substring(start, end + 1 - start);

        ssdlText = ssdlText.Replace(oldProvider, "Provider=\"" + provider + "\"");

        var tempDir = Environment.GetEnvironmentVariable("TEMP") + '\\' + resourceAssembly.GetName().Name;
        Directory.CreateDirectory(tempDir);

        var ssdlOutputPath = tempDir + '\\' + Guid.NewGuid() + ".ssdl";

        using (var outputFile = new FileStream(ssdlOutputPath, FileMode.Create))
        {
            using (var outputStream = new StreamWriter(outputFile))
            {
                outputStream.Write(ssdlText);
            }
        }

        var eBuilder = new EntityConnectionStringBuilder
        {
            Provider = provider,

            Metadata = "res://*/" + modelName + ".csdl"
                        + "|" + ssdlOutputPath
                        + "|res://*/" + modelName + ".msl",

            ProviderConnectionString = providerConnectionString
        };

        return eBuilder.ToString();
    }
}

2) Modifiez le T4 qui crée votre ObjectContext afin qu'il utilise le ConnectionManager:

public partial class MyModelUnitOfWork : ObjectContext
{
    public const string ContainerName = "MyModelUnitOfWork";
    public static readonly string ConnectionString
        = ConnectionManager.GetConnectionString("MyModel");

3) Ajoutez les lignes suivantes à App.Config:

 <? xml version = "1.0" encoding = "utf-8"?> 
 <configuration> 
 <connectionStrings> 
 <add name = "MyModelUnitOfWork" connectionString = ... />
 </connectionStrings> 
 <appSettings> 
 <add key = "MyModelUnitOfWorkConnectionString" value = "data source = MyPc\SqlExpress; initial catalog = MyDB ; sécurité intégrée = True; multipleactiveresultsets = True "/>
 <add key =" MyModelUnitOfWorkProvider "value =" System.Data.SqlClient "/>
 </appSettings> 
 < /configuration>

Le ConnectionManager remplacera ConnectionString et Provider par ce qui se trouve dans App.Config.

Vous pouvez utiliser le même ConnectionManager pour tous les ObjectContexts (afin qu'ils lisent tous les mêmes paramètres depuis App.Config), ou modifier le T4 afin qu'il crée un ConnectionManager pour chacun (dans son propre espace de noms), afin que chacun lise des paramètres distincts.

2
Danny Varod

Ce que je comprends, c'est que vous voulez la même chaîne de connexion avec différentes métadonnées. Vous pouvez donc utiliser une chaîne de connexion comme indiqué ci-dessous et remplacer la partie "". J'ai utilisé votre chaîne de connexion donnée dans la même séquence.

connectionString="<METADATA>provider=System.Data.SqlClient;provider connection string=&quot;Data Source=SomeServer;Initial Catalog=SomeCatalog;Persist Security Info=True;User ID=Entity;Password=SomePassword;MultipleActiveResultSets=True&quot;"

Pour la première connexionString remplacez <METADATA> avec "metadata=res://*/ModEntity.csdl|res://*/ModEntity.ssdl|res://*/ModEntity.msl;"

Pour la deuxième connexionString remplacez <METADATA> avec "metadata=res://*/Entity.csdl|res://*/Entity.ssdl|res://*/Entity.msl;"

Pour la troisième connexion, la chaîne remplace <METADATA> avec "metadata=res://*/Entity.csdl|res://*/Entity.ssdl|res://*/Entity.msl|res://*/ModEntity.csdl|res://*/ModEntity.ssdl|res://*/ModEntity.msl;"

Bon codage!

1
Ravia

Les applications Silverlight n'ont pas d'accès direct à machine.config.

0