27

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

6 回答 6

42

不幸的是,将多个实体上下文组合成一个命名连接是不可能的。如果您想使用 .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" />

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

于 2011-04-28T23:10:53.837 回答
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 

使用这样的配置表,您可以创建如下行: 在此处输入图像描述

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

于 2011-05-04T21:51:57.323 回答
3

首先尝试了解实体框架连接字符串是如何工作的,然后您就会知道哪里出了问题。

  1. 你有两个不同的模型,Entity 和 ModEntity
  2. 这意味着您有两个不同的上下文,每个上下文都有自己的存储模型、概念模型和两者之间的映射。
  3. 您只是简单地组合了字符串,但是 Entity 的上下文如何知道它必须拾取 entity.csdl 而 ModEntity 将拾取 modentity.csdl?好吧,有人可以编写一些智能代码,但我认为这不是 EF 开发团队的主要角色。
  4. machine.config 也是个坏主意。
  5. 如果将 Web 应用程序移动到不同的机器、共享托管环境或出于维护目的,可能会导致问题。
  6. 每个人都可以访问它,你让它变得不安全。如果任何人都可以在服务器上部署 Web 应用程序或任何 .NET 应用程序,他们就可以完全访问您的连接字符串,包括您的敏感密码信息。

另一种选择是,您可以为您的上下文创建自己的构造函数并传递您自己的连接字符串,您可以编写一些 if 条件等来从 web.config 加载默认值

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

于 2011-04-29T09:21:29.667 回答
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 版本="1.0" 编码="utf-8"?>
<配置>
  <连接字符串>
    <add name="MyModelUnitOfWork" connectionString=... />
  </connectionStrings>
  <应用设置>
    <add key="MyModelUnitOfWorkConnectionString" value="数据源=MyPc\SqlExpress;初始目录=MyDB;集成安全=True;multipleactiveresultsets=True" />
    <add key="MyModelUnitOfWorkProvider" value="System.Data.SqlClient" />
  </app设置>
</配置>

ConnectionManager 会将 ConnectionString 和 Provider 替换为 App.Config 中的内容。

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

于 2011-05-05T13:56:30.273 回答
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;"

对于第一个连接字符串替换<METADATA>"metadata=res://*/ModEntity.csdl|res://*/ModEntity.ssdl|res://*/ModEntity.msl;"

对于第二个连接字符串替换<METADATA>"metadata=res://*/Entity.csdl|res://*/Entity.ssdl|res://*/Entity.msl;"

对于第三个连接字符串替换<METADATA>"metadata=res://*/Entity.csdl|res://*/Entity.ssdl|res://*/Entity.msl|res://*/ModEntity.csdl|res://*/ModEntity.ssdl|res://*/ModEntity.msl;"

快乐编码!

于 2011-05-04T12:55:18.790 回答
0

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

于 2011-04-25T17:46:03.767 回答