实体框架的连接字符串

时间:2011-04-25 17:26:07

标签: c# entity-framework machine-config

我想在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; 

6 个答案:

答案 0 :(得分:40)

不幸的是,将多个实体上下文组合到单个命名连接中是不可能的。如果要使用.config文件中的命名连接字符串来定义实体框架连接,则每个连接都必须具有不同的名称。按照惯例,该名称通常是上下文的名称:

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

这样,您可以为计算机上每个项目中的每个上下文使用单个连接字符串。

答案 1 :(得分:5)

您可以使用带有作用域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

然后从您的应用程序dal(s)包装EF,您可以轻松检索范围配置 如果您没有使用dal并直接使用EF在线路中工作,则可以从SystemConfig表中创建一个实体,并根据您所使用的应用程序使用该值。

答案 2 :(得分:3)

首先尝试了解实体框架连接字符串的工作原理,然后您将了解错误。

  1. 您有两种不同的模型,Entity和ModEntity
  2. 这意味着您有两个不同的上下文,每个上下文都有自己的存储模型,概念模型和两者之间的映射。
  3. 您只是简单地组合了字符串,但实体的上下文如何知道它必须拾取e​​ntity.csdl而ModEntity将拾取modentity.csdl?那么有人可以编写一些智能代码,但我认为这不是EF开发团队的主要角色。
  4. 而且machine.config也不错。
  5. 如果将网络应用程序移动到不同的计算机或共享主机环境或用于维护目的,则可能会导致问题。
  6. 每个人都可以访问它,你让它变得不安全。如果任何人都可以在服务器上部署Web应用程序或任何.NET应用程序,他们就可以完全访问您的连接字符串,包括您的敏感密码信息。
  7. 另一种选择是,你可以为你的上下文创建自己的构造函数并传递你自己的连接字符串,你可以编写一些if条件等来从web.config加载默认值

    更好的办法是,保持连接字符串不变,为应用程序池提供一个可以访问数据库服务器的标识,并且不要在连接字符串中包含用户名和密码。

答案 3 :(得分:2)

要启用相同的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)修改创建ObjectContext的T4,使其使用ConnectionManager:

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中的内容。

您可以对所有ObjectContex使用相同的ConnectionManager(因此它们都从App.Config中读取相同的设置),或编辑T4,以便为每个(在其自己的命名空间中)创建一个ConnectionManager,以便每个读取单独的设置

答案 4 :(得分:1)

据我所知,您需要具有不同元数据的相同连接字符串。因此,您可以使用下面给出的连接字符串并替换“”部分。我以相同的顺序使用了你给定的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;"

对于第二个connectionString,将<METADATA>替换为"metadata=res://*/Entity.csdl|res://*/Entity.ssdl|res://*/Entity.msl;"

对于第三个connectionString,将<METADATA>替换为"metadata=res://*/Entity.csdl|res://*/Entity.ssdl|res://*/Entity.msl|res://*/ModEntity.csdl|res://*/ModEntity.ssdl|res://*/ModEntity.msl;"

快乐的编码!

答案 5 :(得分:0)

Silverlight应用程序无法直接访问machine.config。