2011-04-20 36 views
1

我一直在使用我的POCO的Money的自定义类型,并试图将其插入到我的数据库中,但它实际上是由Entity Framework抛弃。EF 4.1使用自定义类型处理钱

这是我的代码变得简单;

我的类型;

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'类型的 声明的属性。 验证该属性是否已被 明确从模型中排除 使用Ignore方法或 NotMappedAttribute数据注释。 确保它是有效的基元 属性。

我想问题是最后一句....那么,什么是有效的原始属性?有没有其他的方式来照顾这个?

+0

每个, 也许你可以帮我:http:// stackoverflow。com/q/6794565/828162 – iuristona 2011-07-22 20:06:24

回答

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类型的某些属性是可空的,所以我必须照顾它。

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

您可以通过显式地映射十进制财产,只露出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; } 
    } 
} 
+0

+1。 EF不支持标量用户类型 – 2011-04-20 18:09:02

+1

好主意。不幸的代码优先不映射保护和私人领域。为了克服这个问题,你必须在每个使你的实体项目EF依赖的实体中使用嵌套的EntityConfiguration。 – 2011-04-20 19:49:26

+0

@拉迪斯拉夫,谢谢,我不知道。这看起来像是一种疏忽,因为我期望它允许保护领域。好吧。我想可以总是暴露两者,或者像你所描述的那样使用EntityConfiguration。 – 2011-04-20 20:26:12

0

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

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

为了获得最好的Struct + ComplexType,你甚至可以同时使用两者:内部使用结构的复杂类型(ComplexType只是一个包装)。