Строки подключения для 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; 

person Rico    schedule 25.04.2011    source источник
comment
Пожалуйста, предоставьте пример кода; Как вы подключаетесь? Это между доменами?   -  person Michael S. Scherotter    schedule 25.04.2011
comment
Тот же компьютер в том же домене. Если у меня есть две отдельные строки подключения, все работает нормально. Но я буду увеличивать количество проектов, и для простоты развертывания я хочу, чтобы все они могли извлекать из той же строки подключения, что и источник данных. то же самое для них всех   -  person Rico    schedule 25.04.2011


Ответы (6)


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

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

person StriplingWarrior    schedule 28.04.2011
comment
Что ж, дело в том, что к этой базе данных будет подключаться множество проектов, и если я изменю базу данных, я не хочу менять 20 строк подключения, чтобы она заработала. Итак, в настоящее время я встроил что-то вроде того, что я исправляю свой вопрос - person Rico; 04.05.2011
comment
@ Рико: Верно. Поэтому поместите только внутреннюю часть строки подключения в Machine.Config, а затем сгенерируйте каждую строку подключения Context на основе этой внутренней строки подключения. - person StriplingWarrior; 04.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 

С помощью такой таблицы конфигурации вы можете создавать такие строки: введите здесь описание изображения

Затем из вашего приложения, обертывающего EF, вы можете легко получить конфигурацию с заданной областью.
Если вы не используете dal(s) и работаете напрямую с EF, вы можете создать Entity из таблицы SystemConfig и используйте значение в зависимости от приложения, в котором вы находитесь.

person Michel Triana    schedule 04.05.2011
comment
Это в основном замена файла конфигурации. Единственное, что вам нужно указать в своих конфигурациях, это имя приложения и SystemConfigConnectionString... все остальное находится в БД. Очень удобно :) - person Michel Triana; 05.05.2011

Сначала попытайтесь понять, как работает строка подключения Entity Framework, тогда вы поймете, что не так.

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

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

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

person Akash Kava    schedule 29.04.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 для каждого (в своем собственном пространстве имен), чтобы каждый считывал отдельные настройки.

person Danny Varod    schedule 05.05.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;"

Для первой строки подключения замените <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;"

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

person Ravia    schedule 04.05.2011

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

person Michael S. Scherotter    schedule 25.04.2011