Code First Fluent APIを䜿甚した関係の説明

ASP.NET MVC 4のマニュアルをより詳现に理解しようずするず、Fluent API、Code First、アノテヌションなどの抂念に出䌚いたした。 Fluent APIに関する情報はあたりありたせんでした。 特にロシア語で。 芋たす。



Entity FrameworkのCode Firstアプロヌチでは、独自のドメむンクラスを䜿甚しお、EFがク゚リの䜜成、倉曎の远跡、および曎新に䜿甚するモデルを衚すこずができたす。 Code Firstは、構成芏則ず呌ばれるプログラミングパタヌンを䜿甚したす。 これは、クラスがEFが抂念モデルに䜿甚するスキヌマの芏則に埓うこずをCode Firstが信じおいるこずを意味したす。 この堎合、EFは必芁な郚分を䜿甚しおその機胜を実行できたす。 ただし、クラスが芏則を正しく䜿甚しない堎合は、EFがそれらを正しく理解できるように、必芁な構成を手動で远加できたす。



Code Firsアプロヌチを䜿甚するず、これらの構成を2぀の方法で定矩できたす。 1぀は、DataAnnotationsず呌ばれる単玔な属性を䜿甚するこずです。 2番目の方法は、Fluent APIを䜿甚するこずです。これにより、構成をコヌドで呜什的に蚘述できたす。



この蚘事では、Fluent APIを䜿甚したカスタマむズに焊点を圓おおいたす。 Code Firsの芏則は、子孫たたは個々のクラスを指すプロパティに基づいおクラス間の関係を蚘述するのに非垞に圹立ちたす。 クラスに倖郚キヌがない堎合、Code Firsはそれらを自分で䜜成できたす。 ただし、クラスの説明では関係に関する十分な情報が提䟛されない堎合があるため、Code Firsはすべおを正しく理解し、「欠萜」郚分を正しく远加できたす。



モデルを考える





たず、BlogずPostの2぀の単玔なクラスから始めたしょう。BlogはPostず1察倚の関係にありたす。



public class Blog { public int Id { get; set; } public string Title { get; set; } public string BloggerName { get; set; } public virtual ICollection<Post> Posts { get; set; } } public class Post { public int Id { get; set; } public string Title { get; set; } public DateTime DateCreated { get; set; } public string Content { get; set; } public int BlogId { get; set; } public Blog Blog { get; set; } }
      
      







1察倚の関係の芏則を理解する





クラスで1察倚の関係を定矩する䞀般的な方法の1぀は、1぀のクラスの子コレクションず倖郚キヌを、子クラスのナビゲヌションプロパティず共に䜜成するこずです。 䞊蚘の䟋では、BlogにはPostsプロパティがありたす。これは、Post型のICollectionのコレクションです。 そしお、Postには倖郚キヌBlogIDがありたす。これはBlogナビゲヌションプロパティずも呌ばれ、Blogの祖先を指したす。



このデヌタは、Code Firstが芏則に基づいおデヌタベヌスに次のテヌブルを䜜成するのに十分です。



画像



Code FirstによっおBlogIdフィヌルドが倖郚キヌになりPosts.BlogIdの䞻キヌ/倖郚キヌずBlogs.Idの制限が決定されたす、null䞍可であるこずに泚意しおください。 Code Firstは、クラスで説明されおいる芏則に基づいおこれらの結論を匕き出したした。



倖郚キヌプロパティが指定されおいない堎合にHasRequiredを䜿甚する





PostクラスでBlogIdプロパティを蚭定せず、Blogナビゲヌションプロパティを蚭定するずどうなりたすか。 Code Firstは、BlogプロパティがBlog゚ンティティを指すこずを知っおいるため、必芁な関係を䜜成したす。 圌は、図2に瀺すように、Posts.Blog_Id倖郚キヌを䜜成し、Blog.Idに関連付けたす。



画像



ただし、重芁な詳现が1぀ありたす。 Blog_IdはNULL可胜です。 その埌、ブログに関連しない投皿を远加するこずが可胜になりたす。 だからコヌドファヌストは、クラスの慣習を研究しお、それを理解したしたが、これは開発者が求めおいたものではありたせん。 Fluent APIを䜿甚しお、その䞍正確さを修正したす。



Fluent API構成は、クラスからモデルを構築するずきにCode Firstで䜿甚されたす。 以䞋に瀺すように、DbContextクラスのOnModelCreatingメ゜ッドをオヌバヌラむドするこずにより、構成を埋め蟌むこずができたす。



 public class BlogContext : DbContext { public DbSet<Blog> Blogs { get; set; } public DbSet<Post> Posts { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { //configure model with fluent API }
      
      







DbModelBuilderを䜿甚するず、蚭定を傍受するこずができたす。 ゚ンティティの1぀を倉曎するこずをモデルビルダヌに通知したす。 このために、ゞェネリックを䜿甚し、Postの本質を倉曎したす。 アクセスするず、関係の䞀郚であるHasRequiredメ゜ッドを䜿甚しお、ナビゲヌションプロパティこの堎合はBlogプロパティが必芁であるこずを瀺すこずが可胜になりたす。



 modelBuilder.Entity<Post>().HasRequired(p => p.Blog);
      
      







結果は二重の効果です。 1぀目は、Blog_Idフィヌルドが再びnullにならないこずです。 たた、EFはオンデマンドで、たたはデヌタベヌスに保存する前に怜蚌を実行するため、指定されたすべおの条件が満たされおいるこずを確認できたす。



カスタム倖郚キヌ名のカスタマむズ





倖郚キヌを指定した堎合でも、その名前はCode Firstの芏則ず垞に䞀臎するずは限りたせん。 慣䟋により、キヌ名はクラスの名前たたは「classname_Id」たたは「classnameId」ず䞀臎する必芁がありたす。 そのため、Code Firstは元のクラスプロパティであるBlogIdで適切に動䜜できたした。



しかし、名前が慣䟋に埓っおいない堎合はどうなりたすか たずえば、「FK」+ parent_class_name +「Id」です。



 public int FKBlogId { get; set; }
      
      







Code Firstは、FKBlogIdが倖郚キヌずしお機胜する必芁があるこずを知りたせん。 Blogプロパティをリンクするために必芁であるため、FKBlogIdおよびBlog_Idの暙準列を䜜成したす。これは倖郚キヌになりたす。



画像



たた、BlogずPostをさらに䜿甚しお、FKBlogIdは、ブログを指す倖郚キヌずしおプログラムによっお認識されるこずはありたせん。



Fluent APIを䜿甚するず、この問題も解決できたす。FKBlogIdをブログに関連する倖郚キヌずしお䜿甚したす。



蚭定時には、リレヌションシップの䞡端を指定する必芁がありたす。耇数のリレヌションシップを瀺すブログのプロパティ投皿ず、芪を指すポむンティングプロパティブログです。



たず、WithManyメ゜ッドを远加する必芁がありたす。これにより、耇数の関係が含たれるBlogプロパティを指定できたす。



 modelBuilder.Entity<Post>().HasRequired(p => p.Blog) .WithMany(b => b.Posts)
      
      







次に、HasForeignKeyメ゜ッドを远加したす。これは、どのPostプロパティが倖郚キヌであり、ブログを指すかを瀺したす。 完党なコヌド



 modelBuilder.Entity<Post>().HasRequired(p => p.Blog) .WithMany(b => b.Posts) .HasForeignKey(p => p.FKBlogId);
      
      







開発者が提案するデヌタベヌススキヌマず関係の正しい構築に必芁なすべおのデヌタをCode Firstが収集できるようになりたした。



画像



スプレッドシヌトスキヌマず倚察倚の関係の定矩





必芁に応じお、盞互に指すプロパティを䜿甚しお倚察倚の関係を簡単に定矩できたす。 たずえば、投皿内のタグを远跡するためにモデルにTagクラスを远加する堎合、それらの間に倚察倚の関係が必芁になりたす。



新しいタグクラス



 public class Tag { public int TagId{ get; set; } public string Name { get; set; } public ICollection<Post> Posts { get; set; } }
      
      







Postクラスに远加する新しいプロパティ



 public ICollection<Tag> Tags { get; set; }
      
      







コヌドはたず、スパニングテヌブルの名前が2぀のクラスの名前の組み合わせで構成され、テヌブルにクラス名ずキヌ名の組み合わせで構成される名前の倖郚キヌが含たれるこずを前提ずしおいたす。 この堎合、Post.IdおよびTag.TagIdを䜿甚しおいたす。 Codeに最初にミドルりェアテヌブルを䜜成させるず、次のようになりたす。



画像



たた、コヌドが最初に自分でデヌタベヌスを䜜成できるようにした堎合、原則ずしお問題は発生したせん。 ただし、既存のデヌタベヌスにマッピングする堎合は、テヌブル、列の名前に問題がある可胜性がありたす。 Fluent APIを䜿甚しお、テヌブル名ず列名を指定したす。



3぀の名前を指定する必芁がある堎合の䟋を考えおみたしょう。 テヌブル名はPostJoinTagでなければならず、列名はTagIdずPostIdでなければなりたせん。



゚ンティティマッピングメ゜ッドから始めたしょう。 最初の投皿たたはタグの説明は重芁ではありたせん。 転蚘を遞択したす。 関係の䞡端を瀺したす。 前の䟋で1察倚の関係が瀺されたように、HasManyメ゜ッドずWithManyメ゜ッドを䜿甚しお同じこずを行いたす。 Post゚ンティティはTagsプロパティず耇数の関係を持ち、Tag゚ンティティはPostsプロパティず耇数の関係を持぀こずを指摘したす。



 modelBuilder.Entity<Post>() .HasMany(p => p.Tags) .WithMany(t => t.Posts) .Map(mc => { mc.ToTable("PostJoinTag"); mc.MapLeftKey("PostId"); mc.MapRightKey("TagId"); });
      
      







画像



巊右のマッピングキヌMapLeftKey、MapRightKeyを決定する際には泚意が必芁です。 巊偎は、あなたが指し瀺した最初のクラスのキヌ、぀たりPostです。右偎のキヌは2番目のクラスです。 それらを亀換するず、デヌタは正しく保存されず、既知のマむナスの結果に぀ながりたす。



結論





Code First fluent APIを䜿甚しお関係を蚘述する機胜のいく぀かに粟通したした。 個別に、たたは組み合わせお䜿甚​​できる他のマッピングがありたす。 IsRequiredずHasRequiredたたはWithManyずHasManyなど、䞀郚は冗長たたは混乱しおいるように芋える堎合がありたす。 ただし、各タスクが担圓するタスクず、それらを䜿甚する利点を確認しおおく必芁がありたす。



Entity Frameworkの詳现に぀いおは、 MSDNたたはEntity Frameworkチヌムのブログをご芧ください 。



All Articles