2015年1月20日 星期二

Entity Framework Code First依屬性(Attribute)設定SQL欄位 (續)

花了點時間把Entity Framework Code First依屬性(Attribute)設定SQL欄位的程式碼Review過一次,總覺得設定的地方怪怪的,GetMethods()以後,指定第幾個到底是為了什麼?

if (propAttr.prop.PropertyType.IsGenericType && propAttr.prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
  methodInfo = entityConfig.GetType().GetMethods().Where(p => p.Name == "Property").ToList()[7];
}
else
{
  methodInfo = entityConfig.GetType().GetMethods().Where(p => p.Name == "Property").ToList()[6];
}
decimalConfig = methodInfo.Invoke(entityConfig, new[] { lambdaExpression }) as DecimalPropertyConfiguration;
decimalConfig.HasPrecision((byte)propAttr.attr.Precision, (byte)propAttr.attr.Scale);

從Debug模式下去看,原來Property有很多,需要指定正確的Type,不然就會發生轉換失敗的錯誤,而部分資料類別又有區分允不允許NULL,所以造就了上面詭異的CODE
判斷有沒有允許NULL後,強制指定對應的資料型別,這個方法在網路上廣為流傳,但這實在是太暴力了,如果哪一天順序被改掉,會有一堆人死在那邊
為了避免這種情況發生,決定嘗試去判斷對應型別有沒有允許NULL,無奈小弟功力不夠深厚,一直找不出解決方法

運氣還不錯的找到了一組原始碼HerrKater/EntityHelper.cs
參考了裡面的ProcessDecimalProperties,在GetMethod取得MethodInfo時,後面傳入的Type[]使用LambdaExpression.GetType()去指定對應型別,這時候就可以找到我們正確的DecimalPropertyConfiguration
MethodInfo methodInfo = entityConfig.GetType().GetMethod("Property", new[] { lambdaExpression.GetType() });
DecimalPropertyConfiguration decimalConfig = methodInfo.Invoke(entityConfig, new[] { lambdaExpression }) as DecimalPropertyConfiguration;
decimalConfig.HasPrecision((byte)propAttr.attr.Precision, (byte)propAttr.attr.Scale);


另外參考了他取得在DbContext內宣告DbSet<>的方法
var contextProperties = typeof (T).GetProperties().Where(p => p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof (DbSet<>));

決定把原本用命名空間做判斷的方式改掉,但是他是用PropertyInfo,然後在迴圈裡面進行轉換,這樣會變更到原本我們的Code,所以做一些調整
var tmplist = typeof(T).GetProperties().Where(p => p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>)).SelectMany(p => p.PropertyType.GetGenericArguments()).Where(t => t.GetProperties(BindingFlags.Public | BindingFlags.Instance).Any(p => p.GetCustomAttribute<DecimalAttribute>() != null));

備註:
取得PropertyInfo以後,要先取PropertyType找出宣告的Type,但是因為有外層的DbSet<>,所以還需要再使用GetGenericArguments()去找出定義的Model

參考:
Entity Framework Code First建立Decimal,並設定大小
Entity Framework Code First依屬性(Attribute)設定SQL欄位
HerrKater/EntityHelper.cs

沒有留言 :

張貼留言

Related Posts Plugin for WordPress, Blogger...