web-dev-qa-db-ja.com

Entity Frameworkの接続文字列

Silverlightの複数のエンティティ間で同じデータベース情報を共有したいのですが、接続文字列の名前をxyzにして、machine.configからその接続文字列に全員がアクセスできるようにします...

エンティティに同じ名前を付けなかったため、エンティティのメタデータ部分は異なります。

そのメタデータセクションに複数のエンティティを配置できますか?

次に例を示します。この接続文字列を使用したいのですが、メタデータセクションに複数のエンティティを配置していることに注意してください。

基本的に、この接続文字列を取得したい

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

そして、この接続文字列

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

この接続文字列を作成するには

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

しかし、それは単に機能しません。どちらのプロジェクトもそれに接続できません。

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

残念ながら、複数のエンティティコンテキストを単一の名前付き接続に結合することはできません。 .configファイルの名前付き接続文字列を使用してEntity Framework接続を定義する場合、それぞれに異なる名前を付ける必要があります。慣例により、その名前は通常、コンテキストの名前です。

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

ただし、名前空間の競合が発生した場合は、任意の名前を使用して、生成時にコンテキストに正しい名前を渡すことができます。

var context = new Entity("EntityV2");

明らかに、ファクトリーまたは依存性注入を使用してコンテキストを生成している場合、この戦略が最適に機能します。

別のオプションは、各コンテキストの接続文字列全体をプログラムで生成し、文字列全体をコンストラクターに渡すことです(名前だけではありません)。

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

このようなものはどうですか:

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; 

... 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" />

このようにして、マシン上のすべてのプロジェクトのすべてのコンテキストに対して単一の接続文字列を使用できます。

41

構成ファイルを使用する代わりに、スコープ設定されたsystemConfigテーブルで構成データベースを使用し、そこにすべての設定を追加できます。

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 

このような構成テーブルを使用すると、次のような行を作成できます。 enter image description here

次に、EFをラップしているアプリケーションdalから、スコープ設定を簡単に取得できます。
dalを使用せず、EFで直接作業している場合は、SystemConfigテーブルからエンティティを作成し、使用しているアプリケーションに応じて値を使用できます。

5
Michel Triana

最初にEntity Framework接続文字列がどのように機能するかを理解しようとすると、何が間違っているのかがわかります。

  1. EntityとModEntityの2つの異なるモデルがあります
  2. つまり、2つの異なるコンテキストがあり、各コンテキストには独自のストレージモデル、概念モデル、および両者間のマッピングがあります。
  3. 文字列を単純に組み合わせましたが、Entityのコンテキストは、entity.csdlをピックアップする必要があることをどのように認識し、ModEntityはmodentity.csdlをピックアップしますか?誰かがインテリジェントなコードを書くことはできますが、それがEF開発チームの主な役割だとは思いません。
  4. また、machine.configは悪い考えです。
  5. Webアプリを別のマシン、共有ホスティング環境、またはメンテナンス目的に移動すると、問題が発生する可能性があります。
  6. 誰もがそれにアクセスできるようになります、あなたはそれを安全ではありません。誰かがサーバーにWebアプリまたは.NETアプリを展開できる場合、機密パスワード情報を含む接続文字列へのフルアクセスを取得します。

別の方法として、コンテキスト用に独自のコンストラクタを作成し、独自の接続文字列を渡し、web.configからデフォルトをロードするif条件などを記述することができます

より良い方法は、接続文字列をそのままにして、データベースサーバーにアクセスできるIDをアプリケーションプールに与え、接続文字列にユーザー名とパスワードを含めないことです。

3
Akash Kava

同じedmxが複数のデータベースとデータベースプロバイダーにアクセスできるようにするには、次の手法を使用します。

1)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)ConnectionManagerを使用するように、ObjectContextを作成するT4を変更します。

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

3)次の行を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 ; integrated security = True; multipleactiveresultsets = True "/>
 <add key =" MyModelUnitOfWorkProvider "value =" System.Data.SqlClient "/>
 </ appSettings> 
 < /configuration>

ConnectionManagerは、ConnectionStringとProviderをApp.Configにあるものに置き換えます。

すべてのObjectContextに同じConnectionManagerを使用して(すべてApp.Configから同じ設定を読み取る)、またはT4を編集して(独自のネームスペースに)各ConnectionManagerを作成し、それぞれが個別の設定を読み取ることができます。

2
Danny Varod

私が理解しているのは、異なるメタデータを含む同じ接続文字列が必要だということです。したがって、以下に示す接続文字列を使用して、「」部分を置き換えることができます。指定されたconnectionStringを同じシーケンスで使用しました。

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

最初のconnectionStringの場合、<METADATA>"metadata=res://*/ModEntity.csdl|res://*/ModEntity.ssdl|res://*/ModEntity.msl;"に置き換えます

2番目のconnectionStringの場合、<METADATA>"metadata=res://*/Entity.csdl|res://*/Entity.ssdl|res://*/Entity.msl;"に置き換えます

3番目のconnectionStringの場合、<METADATA>"metadata=res://*/Entity.csdl|res://*/Entity.ssdl|res://*/Entity.msl|res://*/ModEntity.csdl|res://*/ModEntity.ssdl|res://*/ModEntity.msl;"に置き換えます

ハッピーコーディング!

1
Ravia

Silverlightアプリケーションはmachine.configに直接アクセスできません。