2017-09-13 6 views
2

1つの添付オブジェクトに関連するデータが別のテーブルにあるかどうかを検出できる関数を作成しようとしました。添付オブジェクトにナビゲーションプロパティに関する関連するデータベースがあるかどうかをチェック

私は手動で代わりに子供を削除カスケード削除を避けますが、ユーザーに警告することを期待しています。 これは動的でなければならず、各ナビゲーションプロパティも不明です。 さまざまなクラスインスタンスが多すぎますし、プロパティが毎日変更されているため、ハードコーディングできない場合は、それを1つずつ数えることができます。

私の問題は、Property.GetValue()によって返される値を選択するとボックス化されたオブジェクトであり、内部にも動的な型のコレクションがあるため、レコードを数えずに関連するチェックを行うことができません。

私の質問はどのように私は、オブジェクトをキャストすることができますLINQの方法では、ダイナミック型を参照ICollectionへ変換するのですか?

私は丸一日過ごしたとの回答を得ることができなかった、多分それは、EFの概念の私の誤解であるが、助けてください、多くの感謝!

//Domain Model 
public class Course 
{ 
    [Key] 
    public int CourseID { get; set; } 
    [ForeignKey("CourseID")] 
    public virtual ICollection<CourseTeacher> Teachers { get; set; } 
    [ForeignKey("CourseID")] 
    public virtual ICollection<CourseInfo> CourseInfo { get; set; } 
    [ForeignKey("CourseID")] 
    public virtual ICollection<CourseSession> Sessions { get; set; } 
} 

// Controller Delete Action 
[HttpPost, ActionName("Delete")] 
[ValidateAntiForgeryToken] 
public ActionResult DeleteConfirmed(int id) 
{ 
    Course course = db.Courses.Find(id); 

    bool CannotDel = ValidateRelationalData(typeof(course), course); 

    //if failed, warn the user and stop the delete action otherwise delete this record 
} 

// Public function I was trying to make 
public static bool ValidateRelationalData(Type anyType, dynamic anyInstance) 
{ 
    bool IsExisted = anyType.GetProperties() 
     .Where(p => typeof(IEnumerable).IsAssignableFrom(p.PropertyType) && 
      p.PropertyType != typeof(byte[]) && 
      p.PropertyType != typeof(string) 
     ) 
     .Select(prop => (ICollection)prop.GetValue(anyInstance, null)) 
     .Where(c => c.Count() > 0) 
     .Any(); //(ICollection)prop.GetValue(anyInstance, null)) won't work here, because no specific type 
    return IsExisted; 
} 

答えて

1

私は、エンティティDbSetのナビゲーションプロパティを反復する基本メソッドを作成しました:

private static bool CheckIfAnyNavigationHasData<T>(T o, DbContext context) where T : class 
{ 
    var objectContext = ((IObjectContextAdapter)context).ObjectContext; 
    var elementType = objectContext.CreateObjectSet<T>().EntitySet.ElementType; 
    var navigations = elementType.DeclaredNavigationProperties; 

    var collectionNavigations = typeof(T).GetProperties().Where(w => w.PropertyType.Name.Equals(typeof(ICollection<>).Name) 
                   || w.PropertyType.Name.Equals(typeof(HashSet<>).Name) 
                   || w.PropertyType.Name.Equals(typeof(IList<>).Name)) 
                   .Join(navigations, t => t.Name, n => n.Name, (t, n) => t).ToArray(); 

    foreach (var property in collectionNavigations) 
    { 
     var p = o.GetType().GetProperty(property.Name); 
     if (p == null) 
      continue; 

     var propertyValue = p.GetValue(o); 
     if (propertyValue == null) 
      continue; 

     if ((int)property.PropertyType.GetMethod("get_Count").Invoke(propertyValue, null) > 0) 
      return true; 
    } 

    return false; 
} 

あなたは下の参照を使用必要がありますので、使用

using System.Data.Entity; 
using System.Data.Entity.Infrastructure; 
using System.Linq; 

using (var ctx = new Context()) 
{ 
    var course = ctx.Course.Find(2); 
    var cannotDel = CheckIfAnyNavigationHasData(course, ctx); 
} 
+1

非常に進歩しており、EFの理解が深い、私は本当にあなたのコードをたくさん学び、あなたは私の日を救う(敬礼)。 私が検討していることの1つは、オブジェクト型を制約する必要があるかどうかは、Typeパラメータから派生する必要がありますか? もしそうなら、私たちは署名にそのような制約を加えることができますか?ロジックで検証する必要がありますか?テストされ、まだ勉強している、より多くの質問があるときに戻ってくるだろう、あなたの助けに感謝! – Vincent

+0

btw、.GetMethod( "get_Count")について教えてもらえますか? .Count()を呼び出すのは知っているが、このパターンの仕組みは分かっているので、どのように文字列 "get_Count"を調べるのですか?私はおそらく "accessor_FnName"のように思う? – Vincent

+0

私は、メソッドシグネチャを変更するために投稿を更新しました。 '.GetMethod(" get_Count ")について'私はproperty.PropertyType.GetMethods()でリフレクションメソッドの情報を探しました。私はなぜいくつかの方法は、このパターン、良い質問があるか分からない!敬礼! –

関連する問題