Overriding code-generated DbContext constructor

寵の児 提交于 2019-11-30 23:20:02

问题


I'm sure I've done this before at some stage, but I can't figure out how to now! My scenario:

// This is generated from EDMX
public partial class HOLDbEntities : DbContext
{
    public HOLDbEntities()
            : base("name=HOLDbEntities")
        {
        }
}

Now, I want this connection string to be easily changeable (I want to Implement from the HOLDbEntities), so I need to override this constructor.

I've tried:

public partial class HOLDbEntities
{
    private const string _contextName = "HOLDbEntities";
    public static string ContextName { get { return _contextName; } }

    public HOLDbEntities()
        : base(ContextName)
    {
    }
}

But this throw an error:

HOLDbEntities already defines a member called "HOLDbEntities" with the same parameter types.

I can understand why this errors, but how would I stop the constructor being auto-generated in the first place in order to do what I'm trying to achieve?


回答1:


The best I can suggest is a factory method:

private HOLDbEntities(string contextName) : base(contextName) { }

public static HOLDbEntities Create() {
    return new HOLDbEntities(ContextName);
}

and use HOLDbEntities.Create() rather than new HOLDbEntities().




回答2:


I up-voted the previous accepted answer because it is a fairly elegant way of doing it. However another approach would be to modify the T4 template that generates the dbContext Class.

When using EF DB first you have a .edmx file and under that you have an [Entity].Context.tt file. Go into that file and remove (or modify) the following code:

public <#=code.Escape(container)#>()
        : base("name=<#=container.Name#>")
    {
<#
if (!loader.IsLazyLoadingEnabled(container))
{
#>
        this.Configuration.LazyLoadingEnabled = false;
<#
}

foreach (var entitySet in container.BaseEntitySets.OfType<EntitySet>())
{
    // Note: the DbSet members are defined below such that the getter and
    // setter always have the same accessibility as the DbSet definition
    if (Accessibility.ForReadOnlyProperty(entitySet) != "public")
    {
#>
        <#=codeStringGenerator.DbSetInitializer(entitySet)#>
<#
    }
}
#>

now your context class will generate without a constructor, so you should be able to go and create one in an extended class.




回答3:


i changed the context.tt as follows:

<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext
{
    public <#=code.Escape(container)#>()
        : base("name=<#=container.Name#>")
    {

<#
if (!loader.IsLazyLoadingEnabled(container))
{
#>
        this.Configuration.LazyLoadingEnabled = false;
<#
}
foreach (var entitySet in container.BaseEntitySets.OfType<EntitySet>())
{
    // Note: the DbSet members are defined below such that the getter and
    // setter always have the same accessibility as the DbSet definition
    if (Accessibility.ForReadOnlyProperty(entitySet) != "public")
    {
#>
        <#=codeStringGenerator.DbSetInitializer(entitySet)#>
<#
    }
}
#>
var Method = (typeof(Entities)).GetMethods(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).FirstOrDefault(x => x.Name == "OnModelConstructed");
if (Method!=null) Method.Invoke(this,null);
    }

so i can declare a OnModelConstructed method in a partial class of the context.




回答4:


Here is my solution to the problem. I edit the TT file as Dylan Hayes suggested and replaced the constructor with my own. In my case, i needed to change the schema names of certain schemas only. I set a variable in the config file to tell me what environment I was in and used the right schema.

using System.Configuration;
using System.Data.Entity;
using System.Data.Entity.Core.Mapping;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;
using System.Reflection;
using System.Xml;

namespace WS.Framework.WSJDEData
{

    public partial class WSJDE : DbContext
    {
        public WSJDE()
            : base("name=WSJDE")
        {
            ObjectContext context = (this as IObjectContextAdapter).ObjectContext;

            string environment = ConfigurationManager.AppSettings.Get("Environment");

            const string devCTL = "TESTCTL";
            const string devDTA = "TESTDTA";
            const string qaCTL = "CRPCTL";
            const string qaDTA = "CRPDTA";
            const string prodCTL = "PRODCTL";
            const string prodDTA = "PRODDTA";

            var x = Assembly.GetExecutingAssembly().GetManifestResourceStream("WSJDEData.WSJDE.ssdl");

            XmlReader[] sReaders = new XmlReader[]
                {
                    XmlReader.Create(Assembly.GetExecutingAssembly().GetManifestResourceStream("WSJDEData.WSJDE.ssdl"))
                };

            XmlReader[] mReaders = new XmlReader[]
                {XmlReader.Create(Assembly.GetExecutingAssembly().GetManifestResourceStream("WSJDEData.WSJDE.msl"))};

            StoreItemCollection sCollection = new StoreItemCollection(sReaders);

            ObjectContext objContext = ((IObjectContextAdapter) context).ObjectContext;
            MetadataWorkspace workspace = objContext.MetadataWorkspace;

            EdmItemCollection cCollection = workspace.GetItemCollection(DataSpace.CSpace) as EdmItemCollection;


            StorageMappingItemCollection csCollection = new StorageMappingItemCollection(cCollection, sCollection,
                                                                                         mReaders);

            workspace.RegisterItemCollection(sCollection);
            workspace.RegisterItemCollection(csCollection);

            EntityContainer container = workspace.GetItem<EntityContainer>("WSJDEModelStoreContainer", DataSpace.SSpace);

            foreach (EntitySetBase entitySetBase in container.BaseEntitySets)
            {
                string schema = entitySetBase.Schema;

                if (schema != null)
                {
                    string name = schema.Substring(schema.Length - 3);

                    if (name == "CTL")
                    {
                        switch (environment)
                        {
                            case "Dev":
                                typeof (EntitySetBase).GetField("_schema",
                                                                BindingFlags.NonPublic | BindingFlags.Instance)
                                                      .SetValue(entitySetBase, devCTL);
                                break;
                            case "QA":
                                typeof (EntitySetBase).GetField("_schema",
                                                                BindingFlags.NonPublic | BindingFlags.Instance)
                                                      .SetValue(entitySetBase, qaCTL);
                                break;
                            case "Prod":
                                typeof (EntitySetBase).GetField("_schema",
                                                                BindingFlags.NonPublic | BindingFlags.Instance)
                                                      .SetValue(entitySetBase, prodCTL);
                                break;

                        }
                    }

                    if (name == "DTA")
                    {
                        switch (environment)
                        {
                            case "Dev":
                                typeof (EntitySetBase).GetField("_schema",
                                                                BindingFlags.NonPublic | BindingFlags.Instance)
                                                      .SetValue(entitySetBase, devDTA);
                                break;
                            case "QA":
                                typeof (EntitySetBase).GetField("_schema",
                                                                BindingFlags.NonPublic | BindingFlags.Instance)
                                                      .SetValue(entitySetBase, qaDTA);
                                break;
                            case "Prod":
                                typeof (EntitySetBase).GetField("_schema",
                                                                BindingFlags.NonPublic | BindingFlags.Instance)
                                                      .SetValue(entitySetBase, prodDTA);
                                break;

                        }
                    }
                }
            }
        }
    }
}



回答5:


I used the string interpolations feature of C# 6 in the .tt code generation file.
The generated code becomes

public MyEntities()
            : base($"name={MyConfigurationManager.ConnectionStringKey("MyEntities")}")
{
}

when you use

public <#=code.Escape(container)#>()
    : base($"name={MyConfigurationManager.ConnectionStringKey("<#=container.Name#>")}")

in the .tt file.

public static string ConnectionStringKey(string key) in static class MyConfigurationManager in my case adds the initials of the login to the key and checks whether any connection string in ConfigurationManager.ConnectionStrings has that key in which case that key is returned and otherwise just returns the default key.

So now the connectionstring may be different per-user.
E.g.

<add name="MyEntities" connectionString="metadata=res://*/Base.csdl|res://*/Base.ssdl|res://*/Base.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=localhost;initial catalog=local.base;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />
<add name="MyEntitiesFB" connectionString="metadata=res://*/Base.csdl|res://*/Base.ssdl|res://*/Base.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=localhost;initial catalog=local.fb.base;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />

means that user F.B. uses the latter key while all others the former key.



来源:https://stackoverflow.com/questions/15088426/overriding-code-generated-dbcontext-constructor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!