我一直在为我的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数据注释。 确保它是有效的原语 属性。
我猜问题是最后一句......然后,什么是有效的原始属性?还有其他方法可以解决这个问题吗?
答案 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只是一个包装器)。