【问题标题】:EF 4.1 using custom type handling moneyEF 4.1 使用自定义类型处理资金
【发布时间】:2011-04-20 13:25:44
【问题描述】:

我一直在我的 POCO 中使用 Money 的自定义类型,并尝试将其插入到我的数据库中,但它隐式被 Entity Framework 丢弃了。

这是我的简单代码;

我的类型;

public struct Money
{
    private static decimal _value;

    public Money(Decimal value)
    {
        _value = value;
    }

    public static implicit operator Money(Decimal value)
    {
        return new Money(value);
    }

    public static implicit operator decimal(Money value)
    {
        return _value;
    }
}

我的对象;

public class MyObject
{
    [Key]
    public int Id { get; set; }
    public Money MyMoney { get; set; }
}

我的背景;

public class Data : DbContext
{
    public Data()
        : base("Data Source=.;Database=MyTest;Integrated Security=True")
    {}

    public DbSet<MyObject> MyObject { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {

        modelBuilder.Entity<MyObject>()
            .Property(p => p.MyMoney).HasColumnName("MyMoney");

    }
}

当我使用此代码时,我收到以下错误。

“MyMoney”属性不是 在类型“MyObject”上声明的属性。 确认该属性未被 明确地从模型中排除 使用忽略方法或 NotMappedAttribute 数据注释。 确保它是有效的原语 属性。

我猜问题出在最后一句话……那么,什么是有效的原始属性?有没有其他方法可以解决这个问题?

【问题讨论】:

标签: c# ef-code-first code-first entity-framework-4.1


【解决方案1】:

您可以通过显式映射十进制属性并仅向调用者公开Money 属性来实现:

public class MyObject
{
    [Key]
    public int Id { get; set; }
    protected decimal MyMoney { get; set; }
    public Money MyMoneyStruct 
    { 
        get { return (Money)this.MyMoney; } 
        set { this.MyMoney = (decimal)value; }
    }
}

【讨论】:

  • 好主意。不幸的是,代码优先不会映射受保护和私有字段。要克服这个问题,您必须在每个实体中使用嵌套的 EntityConfiguration,这会使您的实体项目依赖于 EF。
  • @Ladislav,谢谢,我不知道。这似乎是一种疏忽,因为我希望它允许受保护的字段。那好吧。我想人们总是可以同时公开两者,或者按照您的描述使用 EntityConfiguration。
  • @Steve:您也可以使用internal 字段并使用它。有两个问题:默认映射只映射公共成员,EntityConfigurationOnModelCreating 都使用 fluent API,仅限于成员的可访问性。
  • 是的,我确实认为这是一种可能的方式,尽管不是最佳方式,但我被范围的限制所困。还有什么想法吗?我自己有一个,将我的结构改为一个类并使用 ComplexTypeConfiguration。我还没有尝试过,但我会的。
  • 好的,我已经尝试将其改为一个类,它确实为我的自定义类型问题提供了解决方案。尽管在数据库中命名我的字段时引入了其他问题,即 MyMoney_value。因此我选择使用 Steves 解决方案,但使用名为 EFMyMoney 的公共小数
【解决方案2】:

好的,这就是我的解决方案。

public class MyObject
{
    [Key]
    public int Id { get; set; }
    public Money MyMoney { get { return (Money)MyMoneyInternal; } set { MyMoneyInternal = (decimal)value; } }
    private decimal MyMoneyInternal { get; set; }
}

为了能够读取该私有属性,我创建了一个属性扩展,如下所示。由于我的一些 Money 类型的属性是 Nullable 的,所以我也必须注意这一点。

public static class PropertyExtensions
{
    public static PrimitivePropertyConfiguration Property<TClass, TProperty>(this EntityTypeConfiguration<TClass> etc, string propertyName)
        where TClass : class
        where TProperty : struct
    {
        PrimitivePropertyConfiguration returnValue;
        Type type = typeof(TClass);

        var propertyInfo = type.GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);

        ParameterExpression parameterExpression = Expression.Parameter(type, "xyz");
        MemberExpression memberExpression = Expression.Property((Expression)parameterExpression, propertyInfo);

        if (IsNullable(memberExpression.Type))
        {
            returnValue = etc.Property((Expression<Func<TClass, TProperty?>>)Expression.Lambda(memberExpression, parameterExpression));
        }
        else
        {
            returnValue = etc.Property((Expression<Func<TClass, TProperty>>)Expression.Lambda(memberExpression, parameterExpression));
        }

        return returnValue;
    }

    private static bool IsNullable(Type type)
    {
        bool result;

        if (type.IsGenericType)
        {
            var genericType = type.GetGenericTypeDefinition();
            result = genericType.Equals(typeof(Nullable<>));
        }
        else
        {
            result = false;
        }

        return result;
    }
}

然后我可以用它来读取我的私有财产。

modelBuilder.Entity<MyObject>()
            .Property<MyObject, decimal>("MyMoneyInternal").HasColumnName("MyMoney");

感谢史蒂夫带我走向正确的方向。

【讨论】:

    【解决方案3】:

    您也可以在 Complex 类中转换您的“Money”;这将使暴露的属性在您的数据库中内联。只有 Decimal 属性,它看起来像 Money_Value(假设您将 Value 作为属性公开)。假设您将“货币”作为字符串添加到类中。然后,您的数据库中也会有 Money_Currency。

    要向 EF 声明您的类是复杂类型,只需使用 [ComplexType()] 对其进行注释即可。

    为了充分利用 Struct + ComplexType,您甚至可以同时使用两者:在内部使用结构的复杂类型(ComplexType 只是一个包装器)。

    【讨论】:

      猜你喜欢
      • 2022-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-11
      • 1970-01-01
      相关资源
      最近更新 更多