【问题标题】:How to ignore nested enums from mapping如何忽略映射中的嵌套枚举
【发布时间】:2014-08-10 06:03:40
【问题描述】:

为方便起见,我有几个带有嵌套枚举的引用实体。例如:

public class StatusA
{
    public enum Values
    {
        Active = 1,
        Inactive = 2,
        InProgress = 3
    }
}

public class StatusB
{
    public enum Values
    {
        Sent = 1,
        Accepted = 2,
        Expired = 3
    }
}

public class EntityA
{
    public StatusA.Values Status {get; set;}
}

public class EntityB
{
    public StatusB.Values Status {get; set;}
}

我在配置模型时遇到以下异常:“StatusA+Values”类型和“StatusB+Values”类型都具有相同的简单名称“Values”,因此无法使用在同一个模型中。给定模型中的所有类型都必须具有唯一的简单名称。在 Code First fluent API 中使用“NotMappedAttribute”或调用 Ignore 以从模型中显式排除属性或类型。

试图修复它我发现 NotMappedAttribute 不适用于枚举。我还尝试了流畅的 API .Ignore<T>(也需要 ref 类型,而不是枚举)和 .Ignore(IEnumerable<Type>),但没有运气。谷歌搜索也不是很有帮助。

还有其他方法可以从模型中排除这些枚举吗?

【问题讨论】:

  • 试过私人不公开?
  • 谢谢,但必须公开。

标签: c# entity-framework ef-code-first entity-framework-6 ef-fluent-api


【解决方案1】:

只有在您实际包含该类型的属性时,您才应该在模型中获取枚举类型。如果你这样做,不能有任何方式忽略类型,而不忽略属性。并且测试表明,忽略属性足以同时忽略类型。

这是一个最小的完整测试程序,用于获取您遇到的异常:

using System.Data.Entity;
using System.Data.Entity.Infrastructure;

public class A
{
    public int Id { get; set; }

    public E P { get; set; } // #1

    public enum E { }
}

public class B
{
    public int Id { get; set; }

    public E P { get; set; } // #2

    public enum E { }
}

static class Program
{
    static void Main()
    {
        var modelBuilder = new DbModelBuilder(DbModelBuilderVersion.Latest);
        modelBuilder.Entity<A>();
        modelBuilder.Entity<B>();
        var model = modelBuilder.Build(new DbProviderInfo("System.Data.SqlClient", "2012"));
    }
}

很明显,只要#1 和#2 都是模型的一部分,就无法避免映射枚举类型。如果您删除 #1 或 #2(或两者),或使用 NotMapped 属性标记 它们,您将看到您不再遇到现在遇到的异常。

如果您可以避免映射该类型的属性,您也许可以避免重命名枚举类型,如下所示:

public class A
{
    public int Id { get; set; }

    public int PAsInt { get; set; }

    [NotMapped]
    public E P {
        get { return (E) PAsInt; }
        set { PAsInt = (int) value; }
    }

    public enum E { }
}

这是 EF 根本不支持枚举类型时需要的旧方法。不幸的是,这种方法确实意味着查询context.As.Where(a =&gt; a.P == E.C) 将不起作用,因为模型不知道P 属性。它需要写成context.As.Where(a =&gt; a.PAsInt == (int)E.C)。不过,根据您的需要,它可能就足够了。

【讨论】:

  • 感谢您的回答。你是对的,我的模型中有这些属性(枚举类型)。我还更新了问题以反映这一点。不幸的是,我需要映射这些属性,它们需要保存在数据库中。到目前为止,我看到的唯一解决方案是给这些枚举不同的名称。还有其他选择吗?
  • +1 我不知道DbModelBuilder 的这种用法。很好的演示目的!
  • @Jk_xp 有,我已经更新了我的答案。它有时是一个好的选择,有时是一个坏的选择,所以我不知道它是否会被你接受。
  • @GertArnold 谢谢。如果你有兴趣,你也可以使用var compiledModel = model.Compile(); var objectContext = compiledModel.CreateObjectContext&lt;ObjectContext&gt;(new SqlConnection()); 来测试 SQL 生成:Console.WriteLine(((ObjectQuery)objectContext.CreateObjectSet&lt;A&gt;().Where(a =&gt; a.Id == 3)).ToTraceString());(我可能在某个地方的语法有错误,但你应该明白了。)
  • @hvd 谢谢,我将持久化属性称为“StatusId”,将实际枚举称为“Status”,我认为它对我有用。
猜你喜欢
  • 1970-01-01
  • 2012-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多