12

我确定我以前在某个阶段做过这个,但我现在不知道怎么做!我的场景:

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

现在,我希望此连接字符串易于更改(我想从 HOLDbEntities 实现),因此我需要重写此构造函数。

我试过了:

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

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

但这会引发错误:

HOLDbEntities 已经使用相同的参数类型定义了一个名为“HOLDbEntities”的成员。

我可以理解为什么会出现这个错误,但是我将如何阻止构造函数首先自动生成以完成我想要实现的目标?

4

5 回答 5

21

我对之前接受的答案投了赞成票,因为这是一种相当优雅的方式。然而,另一种方法是修改生成 dbContext 类的 T4 模板。

首先使用 EF DB 时,您有一个 .edmx 文件,在该文件下您有一个 [Entity].Context.tt 文件。进入该文件并删除(或修改)以下代码:

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)#>
<#
    }
}
#>

现在您的上下文类将在没有构造函数的情况下生成,因此您应该能够在扩展类中创建一个。

于 2014-01-31T21:24:19.803 回答
10

我能建议的最好的方法是工厂方法:

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

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

并使用HOLDbEntities.Create()而不是new HOLDbEntities().

于 2013-02-26T11:59:23.400 回答
3

我改变了 context.tt 如下:

<#=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);
    }

所以我可以在上下文的部分类中声明一个OnModelConstructed方法。

于 2015-06-23T07:40:49.077 回答
0

这是我对问题的解决方案。我按照 Dylan Hayes 的建议编辑了 TT 文件,并用我自己的构造函数替换了构造函数。就我而言,我只需要更改某些模式的模式名称。我在配置文件中设置了一个变量来告诉我我所处的环境并使用了正确的架构。

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;

                        }
                    }
                }
            }
        }
    }
}
于 2014-03-04T20:40:26.350 回答
0

.tt我在代码生成文件中使用了 C# 6 的字符串插值功能。
生成的代码变成

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

当你使用

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

.tt文件中。

public static string ConnectionStringKey(string key)在我的情况下,在静态类MyConfigurationManager中,将登录名的首字母添加到密钥中,并检查其中的任何连接字符串是否ConfigurationManager.ConnectionStrings具有该密钥,在这种情况下返回该密钥,否则只返回默认密钥。

所以现在每个用户的连接字符串可能不同。
例如

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

表示用户 FB 使用后一个键,而所有其他用户使用前一个键。

于 2019-01-28T15:56:16.560 回答