EF 4.1使用自定义类型处理资金

时间:2011-04-20 13:25:45

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

我一直在为我的POCO使用自定义类型的Money,并尝试将其插入到我的数据库中,但实体框架将隐式抛弃。

这是我的代码变得简单;

我的类型;

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数据注释。   确保它是有效的原语   属性。

我猜问题是最后一句......然后,什么是有效的原始属性?还有其他方法可以解决这个问题吗?

3 个答案:

答案 0 :(得分:3)

您可以通过显式映射十进制属性并仅将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; }
    }
}

答案 1 :(得分:1)

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

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");

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

答案 2 :(得分:0)

你也可以在复杂的课程中改变你的“金钱”;这将使您的数据库中的公开属性成为内联。只有Decimal属性,它看起来像Money_Value(假设您将Value公开为属性)。假设您将“Currency”作为字符串添加到类中。然后,您将在数据库中拥有Money_Currency。

要向EF声明您的类是复杂类型,只需使用[ComplexType()]注释它。

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