2

I´m stuck in a ASP.NET application for a small web site. I´m using EF5 with Oracle´s .Net provider using the database first approach.

All works nicely, except that I need to switch from production to development environment at runtime without touching any configuration file (like Web.config file).

In Oracle, as I want to connect to a different database, I need to call a different connection string. The connection strings I have currently are (EZ notation):

MyProductionUserName/MyProductionPassword@192.168.0.200/XE - For the production environment MyDevUserName/MyDevPassword@192.168.0.200/XE - For the development environment.

When using database first, the EF tool builds me the following model:

namespace DataAccessOracleModel.Model
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;

    public partial class Entities : DbContext
    {
        public Entities()
            : base("name=Entities")
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }

        public DbSet<TABLE1> TABLE1 { get; set; }
        public DbSet<TABLE2> TABLE2 { get; set; }
        public DbSet<TABLE3> TABLE3 { get; set; }
        .
        .
        .
        public DbSet<TABLEn> TABLEn { get; set; }
    }
}

Where TABLE1, TABLE2, TABLE3, TABLEn are all my database tables. I can´t touch the above code as It´s generated automatically.

So, here is what I did already:

Looking at this link and at an answer to my own post here I came out with this classes:

public static class ConnectionHelper
    {
        /// <summary>
        /// Builds the connection string for Entity framework on Oracle.
        /// </summary>
        /// <returns></returns>
        public static EntityConnection BuildOracleConnection(OracleConnectionParams connectionParams)
        {

            string oraConnectionString = "DATA SOURCE=192.168.0.200:1521/XE;PERSIST SECURITY INFO=True;USER ID=MyDevUsername;PASSWORD=MyDevPassword"; /// Test connection string for the development environment

            var entityBuilder = new EntityConnectionStringBuilder
            {
                Provider = "Oracle.ManagedDataAccess.Client", // or System.Data.EntityClient?
                ProviderConnectionString = oraConnectionString,
                Metadata = string.Format(@"res://*/{0}.csdl|
                        res://*/{0}.ssdl|
                        res://*/{0}.msl", connectionParams.ModelName)
            };

            return CreateConnection(connectionParams.UserId, entityBuilder, connectionParams.ModelName);
        }


        /// <summary>
        /// Creates the EntityConnection, based on new schema & existing connectionString. Use reflection to get the model and them 
        /// change the internal files.
        /// </summary>
        /// <param name="schemaName">Name of the schema.</param>
        /// <param name="connectionBuilder">The string builder for the connection string</param>
        /// <param name="modelName">Name of the model.</param>
        /// <returns></returns>
        public 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");

            ///
            /// Get the EF file pointers
            /// 
            if (conceptualReader == null || mappingReader == null || storageReader == null)
            {
                disposeCollection(new[] { conceptualReader, mappingReader, storageReader });
                return null;
            }

            ///
            /// Change the storage reader
            /// 
            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);
        }
    }
}

And

    /// <summary>
    /// Define parameters used for Oracle database connection. Used to build the connection string at runtime.
    /// </summary>
    public class OracleConnectionParams
    {
        /// <summary>
        /// Name of provider
        /// </summary>
        public string Host { get; set; }

        /// <summary>
        /// Database server name 
        /// </summary>
        public string Port { get; set; }

        /// <summary>
        /// Database name
        /// </summary>
        public string Service { get; set; }

        /// <summary>
        /// Model name
        /// </summary>
        public string UserId { get; set; }

        /// <summary>
        /// Model name
        /// </summary>
        public string Password { get; set; }

        /// <summary>
        /// Model name
        /// </summary>
        public string ModelName { get; set; }
    }

But I´m stuck as I came up with 2 different EntityConnections (Entities and the one returned by CreateConnection).. Questions:

I can´t create another Entities, as it was created by the EF tool. I don´t want to touch the EF original code as our approach in development is to change the database and then generate a new EF class (this is done several times a day).

AS I´m using EF5, I don´t have a constructor to change the connection string, as desired.

I need to make work a simple console application like that (non functional):

namespace TestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            SomeFunctionToSetDbContext("192.168.0.200", "1521", "XE", "MyDevUserId", "MyDevPassword");

            var testtableitens = TestTable1.List();

            foreach (var item in testtableitens)
                Console.WriteLine(item);
        }
    }
}

But as I said I don´t know where to go to "join" both ideas... Help very appreciated...

Community
  • 1
  • 1
Mendes
  • 17,489
  • 35
  • 150
  • 263
  • Our team just takes the lazy way of changing the connection string in the Web.Config file during first install. When we deploy an update, we don't replace the Web.Config file on the live machine. Yes, sorry I missed the part at the top that said you don't want to touch web.config – failedprogramming Mar 06 '14 at 23:12
  • We need to get out of Web.config. In Oracle that doesn´t work very well, cos Oracle Schema=Username. So, if the DB was created by a different user we need to create a new EF file. That´s not possible for every customer and we don´t want to fix the Oracle username (we are doing that today). – Mendes Mar 06 '14 at 23:17

0 Answers0