zoukankan      html  css  js  c++  java
  • Entity Framework多对多关系实践(manytomany)

      Entity Framework中有三种关系,一对一(one-to-one),一对多(one-to-many),多对多(many-to-many),前两种就不说了,园子里这方面的文章很多(dudu的:Entity Framework 实践系列,杨延成的:EF框架step by step郝冠军的:Entity Framework系列文章),看过之后简单的使用基本没什么问题,这里要说的是第三种:多对多(many-to-many)。

      这里单独把多对多关系拿出来说,不是因为上述系列文章中没有,只不过需求不同,我的需求用上述系列文章中的方法实现不了。这里先用一个例子说一下我的需求吧:我要用EF处理 question(QID,Title)与tag(TID,TagName)之间的关系,这是一个多对多关系(一个问题有多个标签,一个标签有多个问题),因此在数据库中除了question与tag表外应该还有他们的关系表question_tag表,问题就出在question_tag表上。

      如果我的question_tag表仅仅只有两个字段QID与TID,那么用上面系列文章中提到的方法就可以实现,关键代码如下:

     1     [Table("Question")]
    2 public class Question
    3 {
    4 [Key]
    5 [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    6 public int QID { get; set; }
    7 public string Title { get; set; }
    8 public virtual ICollection<Tag> Tags { get; set; }
    9 }
    10
    11 [Table("Tag")]
    12 public class Tag
    13 {
    14 [Key]
    15 [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    16 public int TID { get; set; }
    17 public string TagName { get; set; }
    18 public virtual ICollection<Question> Questions { get; set; }
    19 }
    20
    21 public class BlogDbContext : DbContext
    22 {
    23 protected override void OnModelCreating(DbModelBuilder modelBuilder)
    24 {
    25 modelBuilder.Entity<Question>()
    26 .HasMany(q => q.Tags)
    27 .WithMany(t => t.Questions)
    28 .Map
    29 (
    30 m =>
    31 {
    32 m.MapLeftKey("QID");
    33 m.MapRightKey("TID");
    34 m.ToTable("Question_Tag");
    35 }
    36 );
    37 base.OnModelCreating(modelBuilder);
    38 }
    39 public IDbSet<Question> Questions { get; set; }
    40 public IDbSet<Tag> Tags { get; set; }
    41 }

      现在的问题是我的question_tag表为了业务需求不仅仅只有这两个字段(这个需求应该很常见,本例中增加一个时间字段DateAdded作为示例),因此用上面的方案就不行了。那么要怎么处理呢,找了好多资料都不行,没办法只好自己动手,丰衣足食。

      首先想到的是,既然question_tag表中还有其它字段,那么这个实体肯定要表现出来。然后想到的是,按原来的方法question跟tag是直接产生联系的,EF根据question和tag的定义可以判断出是多对多关系,但现在加了一个关系实体question_tag,question跟question_tag的关系是一对多,tag跟question_tag的关系也是一对多,因此可以通过question_tag来联接question跟tag(数据库中这个表的存在本来就是这个意思),也就是说question跟tag不直接产生联系。有了上面的想法,经过多次尝试后,我把实体间的关系修改为如下形式:

     1     [Table("Question")]
    2 public class Question
    3 {
    4 [Key]
    5 [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    6 public int QID { get; set; }
    7 public string Title { get; set; }
    8 public virtual ICollection<QuestionTag> QuestionTags { get; set; }
    9 }
    10
    11 [Table("Tag")]
    12 public class Tag
    13 {
    14 [Key]
    15 [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    16 public int TID { get;set;}
    17 public string TagName { get; set; }
    18 public virtual ICollection<QuestionTag> QuestionTags { get; set; }
    19 }
    20
    21 [Table("QuestionTag")]
    22 public class QuestionTag
    23 {
    24 [Key]
    25 [Column(Order=0)]
    26 [ForeignKey("Question")]
    27 public int QID { get; set; }
    28
    29 [Key]
    30 [Column(Order = 1)]
    31 [ForeignKey("Tag")]
    32 public int TID { get; set; }
    33
    34 public DateTime DateAdded { get; set; }
    35
    36 public virtual Question Question { get; set; }
    37
    38 public virtual Tag Tag { get; set; }
    39 }

      有了上面的定义后,DbContext的定义就很简单了,不需要重写OnModelCreating:

    1     public class BlogDbContext : DbContext
    2 {
    3 public IDbSet<Question> Questions { get; set; }
    4 public IDbSet<Tag> Tags { get; set; }
    5 public IDbSet<QuestionTag> QuestionTags { get; set; }
    6 }

    好了,下面开始写测试代码,就是增删改查操作:

      1     public class EFTest
    2 {
    3 public void Insert()
    4 {
    5 using (var db = new BlogDbContext())
    6 {
    7 //添加一个question,两个tag
    8 var question = new Question() { Title = "abc" };
    9 var tagA = new Tag() { TagName = "a" };
    10 var tagB = new Tag() { TagName = "b" };
    11 var qes = db.Questions.Add(question);
    12 var tA = db.Tags.Add(tagA);
    13 var tB = db.Tags.Add(tagB);
    14 db.SaveChanges();
    15
    16 //添加question_tag
    17 var questiontaga = new QuestionTag() { QID = qes.QID, TID = tA.TID, DateAdded = DateTime.Now };
    18 var questiontagb = new QuestionTag() { QID = qes.QID, TID = tB.TID, DateAdded = DateTime.Now };
    19 var qtA = db.QuestionTags.Add(questiontaga);
    20 var qtB = db.QuestionTags.Add(questiontagb);
    21 db.SaveChanges();
    22 Console.WriteLine("Insert Success");
    23
    24 //显示数据
    25 Show();
    26 }
    27 }
    28
    29 public void Delete()
    30 {
    31 using (var db = new BlogDbContext())
    32 {
    33 var qes = db.Questions.SingleOrDefault(q => q.QID == 1);
    34 if (qes != null)
    35 {
    36 db.Questions.Remove(qes);
    37 db.SaveChanges();
    38 Console.WriteLine("Delete Success");
    39
    40 Show();
    41 }
    42 }
    43 }
    44
    45 public void Update()
    46 {
    47 using (var db = new BlogDbContext())
    48 {
    49 var qes = db.Questions.SingleOrDefault(q => q.QID == 2);
    50 if (qes != null)
    51 {
    52 qes.Title = "update abc";
    53 db.SaveChanges();
    54 Console.WriteLine("Update Success");
    55
    56 Show();
    57 }
    58 }
    59 }
    60
    61 public void Select()
    62 {
    63 using (var db = new BlogDbContext())
    64 {
    65 var qes = db.Questions.SingleOrDefault(q => q.QID == 2);
    66 if (qes != null)
    67 {
    68 Console.WriteLine("Select Question:");
    69 Console.Write("QID:"+qes.QID + "\tTitle:" + qes.Title+"\tTag:");
    70 qes.QuestionTags.ForEach(t => Console.Write(t.Tag.TagName+"\t"));
    71 }
    72 Console.WriteLine("\nSelect Success");
    73 }
    74 }
    75
    76 public void Show()
    77 {
    78 using (var db = new BlogDbContext())
    79 {
    80 //显示question
    81 var qes = db.Questions;
    82 if (qes != null)
    83 {
    84 Console.WriteLine("Question:");
    85 qes.ForEach(q =>
    86 {
    87 Console.Write("QID:"+q.QID+"\tTitle:"+q.Title+"\tTag:");
    88 q.QuestionTags.ForEach(t =>
    89 {
    90 Console.Write(t.Tag.TagName+"\t");
    91 });
    92 Console.WriteLine();
    93 });
    94 }
    95
    96 //显示tag
    97 var tag = db.Tags;
    98 if (tag != null)
    99 {
    100 Console.WriteLine("Tag:");
    101 tag.ForEach(t =>
    102 {
    103 Console.Write("TID:" + t.TID + "\tTagName:" + t.TagName + "\tQuestion:");
    104 t.QuestionTags.ForEach(q =>
    105 {
    106 Console.Write(q.Question.Title + "\t");
    107 });
    108 Console.WriteLine();
    109 });
    110 }
    111
    112 Console.WriteLine();
    113 }
    114 }
    115 }

      很幸运地通过了,运行后数据库中生成的表如下:

      要注意的是这里QID和TID不仅仅是PK,也是FK。

      程序的输出如下:

      可以看到程序能很好地满足我的需求。在上面的删除代码中删除了QID为1的question后,数据库中question_tag表中的数据如下:

      我们可以看到,question_tag表中QID为1的数据也同时删除了,正是我们需要的结果。

    最后做个小结吧:

      一直以来都是看的多,写的少,从老鸟那里吸收的多,贡献的少,总怕自己写的不好,以后争取慢慢改变这种状况,把自己学到的知识总结出来,争取能给新手一些帮助吧。

      希望这篇文章对大家有所帮助,当然了,限于水平欢迎大家拍砖,提出更好的解决方案。

    版权

    作者:Artwl

    出处:http://artwl.cnblogs.com

    本文首发博客园,版权归作者跟博客园共有。转载必须保留本段声明,并在页面显著位置给出本文链接,否则保留追究法律责任的权利。

  • 相关阅读:
    Power of Cryptography
    Radar Installation
    Emag eht htiw Em Pleh
    Help Me with the Game
    89. Gray Code
    87. Scramble String
    86. Partition List
    85. Maximal Rectangle
    84. Largest Rectangle in Histogram
    82. Remove Duplicates from Sorted List II
  • 原文地址:https://www.cnblogs.com/artwl/p/2234359.html
Copyright © 2011-2022 走看看