使用自定义类型处理货币
本文关键字:处理 货币 类型 自定义 | 更新日期: 2023-09-27 17:50:35
我一直在使用我的poco的自定义类型的钱,并试图将其插入到我的数据库,但它是隐含的被实体框架抛弃。
这是我的代码简化;
我的类型;
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数据注释。确保它是一个有效的原语财产。
我想问题出在最后一句....那么,什么是有效的基本属性呢?还有其他办法解决这个问题吗?
您可以通过显式映射十进制属性并仅向调用者公开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; }
}
}
好的,这就是我的解决方案。
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");
谢谢Steve给我指明了正确的方向。
你也可以在Complex类中转换你的"Money";这将使暴露的属性内联到数据库中。如果只使用Decimal属性,它看起来就像Money_Value(假设您将Value公开为属性)。假设您将"Currency"作为字符串添加到类中。然后,数据库中也会有Money_Currency。
要向EF声明你的类是一个复杂类型,只需用[ComplexType()]注释它。
为了获得Struct + ComplexType的最佳效果,您甚至可以同时使用两者:复杂类型在内部使用结构(ComplexType只是一个包装器)。