2011-08-08 8 views
8

私はこの問題を解決しようと数日を費やしました。私の問題を例証する簡単なプロジェクトを作っているうちに、私は考えられる解決策を見つけました。だから、これは二重問題のようなものです。エンティティフレームワーク、コードファーストモデリングと循環参照

しかし、最初に、少し背景情報:

私はちょうど私のASP.NET MVCプロジェクトのためのモデルを作成するために、エンティティフレームワーク4.1(EF)とコードファーストを使い始めました。 Iこれに似たいくつかのモデルが必要です。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 

namespace TestApp.Models 
{ 
    public class Family 
    { 
     public int ID { get; set; } 
     public string Name { get; set; } 

     public virtual ICollection<Father> Fathers { get; set; } 
     public virtual ICollection<Mother> Mothers { get; set; } 
    } 

    public class Mother 
    { 
     public int ID { get; set; } 
     public string Name { get; set; } 
     public int FamilyID { get; set; } 

     public virtual ICollection<Child> Children { get; set; } 
     public virtual Family Family { get; set; } 
    } 

    public class Father 
    { 
     public int ID { get; set; } 
     public string Name { get; set; } 
     public int FamilyID { get; set; } 

     public virtual ICollection<Child> Children { get; set; } 
     public virtual Family Family { get; set; } 
    } 

    public class Child 
    { 
     public int ID { get; set; } 
     public string Name { get; set; } 
     public int MotherID { get; set; } 
     public int FatherID { get; set; } 

     public virtual Mother Mother { get; set; } 
     public virtual Father Father { get; set; } 
    } 
} 

とDbContext:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Data.Entity; 

namespace TestApp.Models 
{ 
    public class TestContext : DbContext 
    { 
     public DbSet<Family> Families { get; set; } 
     public DbSet<Mother> Mothers { get; set; } 
     public DbSet<Father> Fathers { get; set; } 
     public DbSet<Child> Children { get; set; } 
    } 
} 

を(ラメ例を言い訳してください、それは私の金曜日揚げ脳が思い付くことができたものです。)

家族は複数の母親と複数の父親を持つことができます。子供には母親と父親がいます。私は私の仕事で.NETの看護師の一人にチェックしました。私の仕事では、これに特別なことは何もないと同意しました。少なくとも私たちが見る限り。

しかし、私は、コードを実行したとき、私はこの例外を取得:

System.Data.SqlServerCe.SqlCeException:参照関係が許可されていない、循環参照になります。 [Constraint name = Mother_Family]

サイクルが表示されます:Family - Mother - Child - Father - Family。しかし、私が自分でデータベーステーブルを作成した場合(私が気に入らないのは、コードファーストについて好きなことです)、私の言う限り、完全に有効なデータ構造になります。

私の最初の質問は次のとおりです。最初にコードを使用すると、これが問題になるのはなぜですか?サイクルを適切に処理する方法をEFに伝える方法はありますか?

私が最初に書いたように、私の問題を具体化するための単純なプロジェクトを作成しているうちに、私は偶然、解決策を見つけました。モデルを定義するときにいくつかのプロパティを忘れてしまっただけです。次の例では明確にするために、代わりにそれらを除去する、私は忘れてしまったモデルの部分をコメントアウトしました:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 

namespace TestApp.Models 
{ 
    public class Family 
    { 
     public int ID { get; set; } 
     public string Name { get; set; } 

     public virtual ICollection<Father> Fathers { get; set; } 
     public virtual ICollection<Mother> Mothers { get; set; } 
    } 

    public class Mother 
    { 
     public int ID { get; set; } 
     public string Name { get; set; } 
     // public int FamilyID { get; set; } 

     public virtual ICollection<Child> Children { get; set; } 
     public virtual Family Family { get; set; } 
    } 

    public class Father 
    { 
     public int ID { get; set; } 
     public string Name { get; set; } 
     // public int FamilyID { get; set; } 

     public virtual ICollection<Child> Children { get; set; } 
     public virtual Family Family { get; set; } 
    } 

    public class Child 
    { 
     public int ID { get; set; } 
     public string Name { get; set; } 
     // public int MotherID { get; set; } 
     // public int FatherID { get; set; } 

     public virtual Mother Mother { get; set; } 
     public virtual Father Father { get; set; } 
    } 
} 

ので、これらSomethingID参照プロパティを削除すると、私の問題を解決しているようです。私がこの記事の最後にリンクしているサンプルプロジェクトのコントローラで見てきたように、私はまだ周りを循環して何も問題なくmothers.First().Family.Fathers.First().Children.First().Mother.Family.Nameのようなことをすることができます。しかし、私が見てきたEFやコードファーストモデリングに関するチュートリアルや例(例:this one by Scott Guthrie)にはこれらのプロパティが含まれているため、それらを使用しないように間違っていると感じています。

したがって、私の2番目の質問は次のとおりです。私はまだこれを発見していない欠点と問題がありますか?

ここでプロジェクトの例をダウンロード:http://blackfin.cannedtuna.org/cyclical-reference-test-app.zip、TestSolution.slnを開きます。このプロパティは、サンプルプロジェクトでコメント化されています。 TestModels.csの行のコメントを外してプロパティを追加し、周期的な参照例外を発生させます。

NB:解決策は、c:\ TestAppにあるSQL CEデータベースを作成してシードすることです。

アップデート、2011年12月自衛隊: 私は技術的にこの問題を解決したことがないが、私は私の仕事をやめ、私はマイクロソフトのテクノロジを使用する必要はありません別の仕事を見つけました。この種の解決済み私の問題:

問題を修正するときに書いた古い場所での技術サポートとして: "回避策または解決策が提供されました"。

+0

私がSFで読んだより良い質問の1つ。よくやった。あなたの「回避策」がありがとう! –

答えて

0

これは既知の問題です。これは、最初の問題ではありません。私が聞いたことから、WCFの今後のバージョンではより良いソリューションに取り組んでいると聞いていますが、当然のことながら、データ構造を変えるためにデータを表すDataContractsを作成するほうがはるかに優れています。循環参照を削除します。

私はそれが痛いことは知っていますが、クライアントがデータベースに存在するオブジェクトを再生させるのではなく、クライアントが消費する構造に他の変更を加える可能性が高いという点で、 (私は、コードファーストについて好きなんだ、私はないに好む、 )

+0

ただし、シリアル化のためのデータの記述にDataContractsは使用されていませんか?私はまだシリアル化さえしていない。 – decibyte

3

しかし、私は、データベーステーブルを自分で作成した場合、それは私の知る限り、完全に有効な データ構造になります。

これは再確認する必要があります。この例外は、データベースから直接取得され、Entity Frameworkでは発生しません。手作業で作成された同じ制約を持つテーブル構造も無効になる可能性があります。外部キーのプロパティMother.FamilyIDFather.FamilyIDChild.MotherID、およびChild.FatherIDは、はnullではありませんです。したがって、それらは必要な関係を表し、データベースの対応する列もNULL可能ではありません。

モデルクラスからこれらのプロパティをすべて削除すると、関係が突然になります。ナビゲーションプロパティはnullになる可能性があるためです。これはDBのFK列がNULL可能なので、今度は別のモデルです!明らかにこれは許可されたモデルです。

あなたが代わりにあなたがNULL可能なタイプを使用することができます必要な関係のオプションを表すモデルでまだ外部キープロパティを持つようにしたい場合:public int? FamilyID { get; set; }を、public int? MotherID { get; set; }など