Строки подключения для Entity Framework - PullRequest
27 голосов
/ 25 апреля 2011

Я хочу совместно использовать одну и ту же информацию базы данных для нескольких объектов в 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 ]

40 голосов
/ 29 апреля 2011

К сожалению, объединение нескольких контекстов сущностей в одно именованное соединение невозможно.Если вы хотите использовать именованные строки подключения из файла .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; 

... со следующим вyour 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" />

Таким образом, вы можете использовать одну строку подключения для каждого контекста в каждом проекте на машине.

5 голосов
/ 05 мая 2011

Вместо использования файлов конфигурации вы можете использовать базу данных конфигурации с областью видимости 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 (s) и не работаете в проводном режиме напрямую с EF, вы можете создать Entity из таблицы SystemConfig и использовать значение в зависимости от того, в каком приложении вы находитесь.

3 голосов
/ 29 апреля 2011

Сначала попытайтесь понять, как работает строка Entity Framework Connection, затем вы поймете, что не так.

  1. У вас есть две разные модели, Entity и ModEntity
  2. Это означает, что выимеют два разных контекста, каждый контекст имеет свою собственную модель хранения, концептуальную модель и отображение между ними.
  3. Вы просто скомбинировали строки, но как контекст Entity узнает, что он должен забрать entity.csdl и ModEntityпикап modentity.csdl?Кто-то может написать какой-то интеллектуальный код, но я не думаю, что это главная роль команды разработчиков EF.
  4. Также machine.config - плохая идея.
  5. Если веб-приложения перемещаются на другую машину, илив среду общего хостинга или в целях обслуживания это может привести к проблемам.
  6. Каждый сможет получить к нему доступ, вы делаете его небезопасным.Если кто-либо может развернуть веб-приложение или любое приложение .NET на сервере, он получит полный доступ к вашей строке подключения, включая вашу конфиденциальную информацию о пароле.

Другой альтернативой является то, что вы можете создать свой собственный конструктор для своегоконтекст и передать свою собственную строку подключения, и вы можете написать некоторые условия if и т.д. для загрузки значений по умолчанию из web.config

Лучше было бы сделать так: оставить строки подключения такими, какие они есть, дать вашему пулу приложений идентификатор, которыйбудет иметь доступ к вашему серверу базы данных и не включать имя пользователя и пароль в строку подключения.

2 голосов
/ 05 мая 2011

Чтобы разрешить одному и тому же 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) Измените T4это создает ваш ObjectContext так, чтобы он использовал 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.

Вы можете использовать один и тот же ConnectionManager для всех ObjectContexts (чтобы они все считывали одни и те же настройки из App.Config), или отредактировать T4, чтобы он создавал один ConnectionManager для каждого (в своем собственном пространстве имен), чтобы каждый из них считывал отдельные настройки.

1 голос
/ 04 мая 2011

Я понимаю, что вам нужна одна и та же строка подключения с разными метаданными. Таким образом, вы можете использовать строку подключения, как указано ниже, и заменить "" часть. Я использовал данную строку подключения в той же последовательности.

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

Для первого соединения String заменить <METADATA> на "metadata=res://*/ModEntity.csdl|res://*/ModEntity.ssdl|res://*/ModEntity.msl;"

Для второго соединения String заменить <METADATA> на "metadata=res://*/Entity.csdl|res://*/Entity.ssdl|res://*/Entity.msl;"

Для третьего соединения String заменить <METADATA> на "metadata=res://*/Entity.csdl|res://*/Entity.ssdl|res://*/Entity.msl|res://*/ModEntity.csdl|res://*/ModEntity.ssdl|res://*/ModEntity.msl;"

Удачного кодирования!

0 голосов
/ 25 апреля 2011

Приложения Silverlight не имеют прямого доступа к machine.config.

...