简体   繁体   English

实体框架的连接字符串

[英]Connection Strings for Entity Framework

I want to share same Database information across multiple entities in Silverlight.. but I want the connection string to be named xyz and have everyone access that connection string from machine.config... 我想在Silverlight中的多个实体之间共享相同的数据库信息..但我希望连接字符串被命名为xyz并让每个人都从machine.config访问该连接字符串...

The meta data part of the entities will be different since I didn't name the entities the same.. 实体的元数据部分将是不同的,因为我没有将实体命名为相同的..

Can I put multiple entities in that metadata section? 我可以在该元数据部分放置多个实体吗?

Here is an example.. I want to use this connection string but note that i put multiple entities in the metadata section.. 这是一个例子..我想使用这个连接字符串,但请注意我在元数据部分放了多个实体。

Basically I want to take this Connection String 基本上我想要这个连接字符串

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

And this Connection String 而这个连接字符串

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

To make this Connection String 制作此连接字符串

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

But it simply doesn't work. 但它根本行不通。 Neither project can connect to it. 这两个项目都无法连接到它。

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

Unfortunately, combining multiple entity contexts into a single named connection isn't possible. 不幸的是,将多个实体上下文组合成单个命名连接是不可能的。 If you want to use named connection strings from a .config file to define your Entity Framework connections, they will each have to have a different name. 如果要使用.config文件中的命名连接字符串来定义实体框架连接,则每个连接都必须具有不同的名称。 By convention, that name is typically the name of the context: 按照惯例,该名称通常是上下文的名称:

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

However, if you end up with namespace conflicts, you can use any name you want and simply pass the correct name to the context when it is generated: 但是,如果最终出现命名空间冲突,则可以使用所需的任何名称,并在生成时将其正确地传递给上下文:

var context = new Entity("EntityV2");

Obviously, this strategy works best if you are using either a factory or dependency injection to produce your contexts. 显然,如果您使用工厂或依赖注入来生成上下文,则此策略最有效。

Another option would be to produce each context's entire connection string programmatically, and then pass the whole string in to the constructor (not just the name). 另一种选择是以编程方式生成每个上下文的整个连接字符串,然后将整个字符串传递给构造函数(而不仅仅是名称)。

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

How about something like this: 这样的事情怎么样:

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; 

... with the following in your machine.config: ...在你的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" />

This way, you can use a single connection string for every context in every project on the machine. 这样,您可以为计算机上每个项目中的每个上下文使用单个连接字符串。

Instead of using config files you can use a configuration database with a scoped systemConfig table and add all your settings there. 您可以使用带有作用域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 

With such configuration table you can create rows like such: 使用这样的配置表,您可以创建如下行: 在此输入图像描述

Then from your your application dal(s) wrapping EF you can easily retrieve the scoped configuration. 然后从您的应用程序dal(s)包装EF,您可以轻松检索范围配置。
If you are not using dal(s) and working in the wire directly with EF, you can make an Entity from the SystemConfig table and use the value depending on the application you are on. 如果您没有使用dal并直接使用EF在线路中工作,则可以从SystemConfig表中创建一个实体,并根据您所使用的应用程序使用该值。

First try to understand how Entity Framework Connection string works then you will get idea of what is wrong. 首先尝试了解实体框架连接字符串的工作原理,然后您将了解错误。

  1. You have two different models, Entity and ModEntity 您有两个不同的模型,Entity和ModEntity
  2. This means you have two different contexts, each context has its own Storage Model, Conceptual Model and mapping between both. 这意味着您有两个不同的上下文,每个上下文都有自己的存储模型,概念模型和两者之间的映射。
  3. You have simply combined strings, but how does Entity's context will know that it has to pickup entity.csdl and ModEntity will pickup modentity.csdl? 你只是组合了字符串,但实体的上下文如何知道它必须拾取e​​ntity.csdl而ModEntity将拾取modentity.csdl? Well someone could write some intelligent code but I dont think that is primary role of EF development team. 那么有人可以编写一些智能代码,但我不认为这是EF开发团队的主要角色。
  4. Also machine.config is bad idea. 还有machine.config是个坏主意。
  5. If web apps are moved to different machine, or to shared hosting environment or for maintenance purpose it can lead to problems. 如果将Web应用程序移动到不同的计算机或共享主机环境或用于维护目的,则可能会导致问题。
  6. Everybody will be able to access it, you are making it insecure. 每个人都可以访问它,你让它变得不安全。 If anyone can deploy a web app or any .NET app on server, they get full access to your connection string including your sensitive password information. 如果任何人都可以在服务器上部署Web应用程序或任何.NET应用程序,则他们可以完全访问您的连接字符串,包括敏感密码信息。

Another alternative is, you can create your own constructor for your context and pass your own connection string and you can write some if condition etc to load defaults from web.config 另一个替代方案是,您可以为您的上下文创建自己的构造函数并传递您自己的连接字符串,您可以编写一些if条件等来从web.config加载默认值

Better thing would be to do is, leave connection strings as it is, give your application pool an identity that will have access to your database server and do not include username and password inside connection string. 更好的办法是,保持连接字符串不变,为应用程序池提供一个可以访问数据库服务器的标识,并且不要在连接字符串中包含用户名和密码。

To enable the same edmx to access multiple databases and database providers and vise versa I use the following technique: 要使相同的edmx能够访问多个数据库和数据库提供程序,反之亦然,我使用以下技术:

1) Define a ConnectionManager: 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) Modify the T4 that creates your ObjectContext so that it will use the ConnectionManager: 2)修改创建ObjectContext的T4,以便它将使用ConnectionManager:

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

3) Add the following lines to App.Config: 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>

The ConnectionManager will replace the ConnectionString and Provider to what ever is in the App.Config. ConnectionManager将ConnectionString和Provider替换为App.Config中的内容。

You can use the same ConnectionManager for all ObjectContexts (so they all read the same settings from App.Config), or edit the T4 so it creates one ConnectionManager for each (in its own namespace), so that each reads separate settings. 您可以对所有ObjectContexts使用相同的ConnectionManager(因此它们都从App.Config读取相同的设置),或编辑T4,以便为每个(在其自己的命名空间中)创建一个ConnectionManager,以便每个读取单独的设置。

What I understand is you want same connection string with different Metadata in it. 我的理解是你想要相同的连接字符串与不同的元数据。 So you can use a connectionstring as given below and replace "" part. 因此,您可以使用下面给出的连接字符串并替换“”部分。 I have used your given connectionString in same sequence. 我以相同的顺序使用了你给定的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;"

For first connectionString replace <METADATA> with "metadata=res://*/ModEntity.csdl|res://*/ModEntity.ssdl|res://*/ModEntity.msl;" 对于第一个connectionString,将<METADATA>替换为"metadata=res://*/ModEntity.csdl|res://*/ModEntity.ssdl|res://*/ModEntity.msl;"

For second connectionString replace <METADATA> with "metadata=res://*/Entity.csdl|res://*/Entity.ssdl|res://*/Entity.msl;" 对于第二的connectionString替换<METADATA>"metadata=res://*/Entity.csdl|res://*/Entity.ssdl|res://*/Entity.msl;"

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

Happy coding! 快乐的编码!

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM