c#实体框架EF 4.1在运行时更改架构和数据库名称

时间:2013-08-30 12:26:36

标签: c# database oracle entity-framework-4 schema

我搜索了一些主题,但没有找到解决问题的具体方法。

我的应用是一款c#商业应用。我先使用EF 4.1数据库。我从开发数据库连接生成模型,并创建一个Model.edmx文件和所有EF的东西很好。

我的目标是为客户提供一个应用程序,让他自己创建数据库和数据库用户。这样做,在运行时我会得到用户名,密码,数据库连接和模式名称参数来连接到客户数据库。这样,部署应用程序我需要的只是让客户创建一个数据库并将数据库参数添加到app配置文件中。

因此,我的目标是在运行时更改连接字符串和架构参数,而不更改所有自动生成的edmx文件,而不是触及VS生成的代码。

我环顾四周,发现:

对于EF早期版本:

Changing schema name on runtime - Entity Framework

http://efmodeladapter.codeplex.com

所有其他帖子都是这样的。我甚至尝试使用第一个邮政编码但没有成功。

但是我已经看到EF 4.1带有更好的支持工具来做到这一点,但我找不到它的参考或例子。重要的是不要从VS更改自动生成的代码。

我是EF的新手,所以我想请求帮助来完成以下任务: a)在运行时更改连接字符串,添加我的用户名,密码和数据库服务器/端口参数 b)更改数据库架构

我使用Oracle作为数据库服务器(因为Oracle将架构和用户混合在一起,这会使事情变得更糟)。

1 个答案:

答案 0 :(得分:4)

实际上,我也需要解决方案。我迅速制定了解决方案,效果很好。我没有在互联网上找到太多关于此的信息,所以我不确定“EF 4.1附带了更好的支持工具”。

具体示例“在运行时更改模式名称 - 实体框架”对我来说并不完全有效,但是通过一些小的修改我得到了它。

这是一个可以执行此操作的DatabaseUtils类:

internal static class DatabaseUtils
{
    /// <summary>
    /// Builds the connection string for Entity framework.
    /// </summary>
    /// <returns></returns>
    public static EntityConnection BuildConnection(BuildConnectionParams buildConnectionParams)
    {
        var sqlBuilder = new SqlConnectionStringBuilder
            {
                DataSource = buildConnectionParams.ServerName,
                InitialCatalog = buildConnectionParams.DatabaseName,
                IntegratedSecurity = true
            };

        var providerString = sqlBuilder.ToString();
        var entityBuilder = new EntityConnectionStringBuilder
        {
            Provider = buildConnectionParams.ProviderName,
            ProviderConnectionString = providerString,
            Metadata = string.Format(@"res://*/{0}.csdl|
                        res://*/{0}.ssdl|
                        res://*/{0}.msl", buildConnectionParams.ModelName)
        };

        return CreateConnection(buildConnectionParams.SchemaName, entityBuilder, buildConnectionParams.ModelName);
    }


    /// <summary>
    /// Creates the EntityConnection, based on new schema & existing connectionString
    /// </summary>
    /// <param name="schemaName">Name of the schema.</param>
    /// <param name="connectionBuilder"></param>
    /// <param name="modelName">Name of the model.</param>
    /// <returns></returns>
    private static EntityConnection CreateConnection(string schemaName, EntityConnectionStringBuilder connectionBuilder, string modelName)
    {
        Func<string, Stream> generateStream =
            extension => Assembly.GetExecutingAssembly().GetManifestResourceStream(string.Concat(modelName, extension));

        Action<IEnumerable<Stream>> disposeCollection = streams =>
        {
            if (streams == null)
                return;

            foreach (var stream in streams.Where(stream => stream != null))
                stream.Dispose();
        };

        var conceptualReader = generateStream(".csdl");
        var mappingReader = generateStream(".msl");
        var storageReader = generateStream(".ssdl");

        if (conceptualReader == null || mappingReader == null || storageReader == null)
        {
            disposeCollection(new[] { conceptualReader, mappingReader, storageReader });
            return null;
        }

        var storageXml = XElement.Load(storageReader);

        foreach (var entitySet in storageXml.Descendants())
        {
            var schemaAttribute = entitySet.Attributes("Schema").FirstOrDefault();
            if (schemaAttribute != null)
                schemaAttribute.SetValue(schemaName);
        }

        storageXml.CreateReader();

        var workspace = new MetadataWorkspace();

        var storageCollection = new StoreItemCollection(new[] { storageXml.CreateReader() });
        var conceptualCollection = new EdmItemCollection(new[] { XmlReader.Create(conceptualReader) });
        var mappingCollection = new StorageMappingItemCollection(conceptualCollection, 
                                                                storageCollection,
                                                                new[] { XmlReader.Create(mappingReader) });

        workspace.RegisterItemCollection(conceptualCollection);
        workspace.RegisterItemCollection(storageCollection);
        workspace.RegisterItemCollection(mappingCollection);

        var connection = DbProviderFactories.GetFactory(connectionBuilder.Provider).CreateConnection();
        if (connection == null)
        {
            disposeCollection(new[] { conceptualReader, mappingReader, storageReader });
            return null;
        }

        connection.ConnectionString = connectionBuilder.ProviderConnectionString;
        return new EntityConnection(workspace, connection);
    }
}

用法:

/// <summary>
/// Initializes a new instance of the <see cref="DynamicAQDContext"/> class.
/// </summary>
public DynamicAQDContext()
{
    var entityConnection = DatabaseUtils.BuildConnection(new BuildConnectionParams
    {
        ProviderName = "System.Data.SqlClient",
        ServerName = "localhost\\",
        DatabaseName = "",
        ModelName = "YOURMODEL",
        SchemaName = "SCHEMA"
    });

    if(entityConnection == null)
        throw new Exception("Can't create EntityConnection");

    _entities = new LINKEntities(entityConnection);
}

可在此处找到更多信息:http://bestplayah.com/entity-framework-dynamic-schema-changes-using-database-first-approach/