存储具有多个相同项目的集合

时间:2015-07-20 13:40:57

标签: c# sql sql-server entity-framework

我使用EF将数据存储到SQL Server数据库中。

有两种类型的数据:

  1. 图像
  2. 符号
  3. 每个符号都包含一组图像

    public virtual ICollection<Image> Images { get; set; }
    

    每个图像都包含一组符号:

    public virtual ICollection<Symbol> Symbols { get; set; }
    

    EF为多对多关系创建关系表。

    如果创建(上传)了新符号,如果这些图像已经上传,程序会查看图像表。

    如果是,则将添加到新符号的图像列表中。

    现在有一个带有3个图像的符号(全部相同!),它将被添加到Symbols表中。

    但是在关系表中只创建了一个条目!?

    所以下次从数据库中读出Symbol时,它只包含1张图片......

    我做错了什么?

    或者这样做的正确方法是什么?

    表格结构:

    [Table("Images")]
    public class SqlSymbolImgInfo
    {
        [Key]
        public int Id { get; set; }
    
        public String Path { get; set; }
        public long Size { get; set; }
        public String Md5 { get; set; }
        public int X { get; set; }
        public int Y { get; set; }
    
        public virtual ICollection<SqlSymbol> Symbols { get; set; }
    
        public override int GetHashCode()
        {
            return System.IO.Path.GetExtension(Path ?? "x.png").GetHashCode() + Size.GetHashCode() + (Md5 ?? "").GetHashCode();
        }
    }
    
    [Table("Symbols")]
    public class SqlSymbol
    {
        [Key]
        public int Id { get; set; }
    
        public String Description { get; set; }
        public int Type { get; set; }
    
        public virtual ICollection<SqlSymbolImgInfo> Images { get; set; }
    }
    

    enter image description here

    创建关系:

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.PluralizingTableNameConvention>();
    
            modelBuilder.Entity<SqlSymbol>().HasMany(s => s.Images).WithMany(i => i.Symbols);
    
            base.OnModelCreating(modelBuilder);
        }
    

    添加符号:

    1. 添加图像(如果不存在)

    2. 获取添加的图片

    3. 添加符号

      public void AddSymbol(Symbol sym)
      {
          try
          {
              using (var db = new Db())
              {
                  // check if images already exists or add them..
                  foreach (var img in sym.Images)
                  {
                      var exImg = db.FindImage(img);
                      if (exImg == null)
                      {
                          var newImg = db.Images.Add(img.ConvertToSqlSymbolImgInfo());
                          db.SaveChanges();
                          img.Id = newImg.Id; // get Id of new image
                      }
                      else
                      {
                          img.Id = exImg.Id; // get Id of existing image
                      }
                  }
      
                  var sqlSym = sym.ConvertToSqlSymbol();
                  // get the existing entries, otherwise the same image will be added again and again...
                  sqlSym.Images = sym.Images.Select(i => db.Images.Find(i.Id)).ToList();
      
                  db.Symbols.Add(sqlSym);
                  db.SaveChanges();
                  sym.Id = sqlSym;
              }
          }
          catch { logIt("error while adding a symbol."); }
      }
      
    4. 解释:

      我需要为实体框架使用包装类,SymbolImage类的原因在共享库中。 而且我不想将EF包含在所有其他项目中,即使我不在那里使用它。

      一些额外的信息:

      带有3张相同图像的符号:

      enter image description here

      添加后的收集和&#34;搜索&#34;图像:

      enter image description here

      将此Symbol添加到数据库后,请查看表格:

      Images表:

      enter image description here

      和关系表:

      enter image description here

      !!标记的行应该有3次?!

      标识为50的Symbol,其中有Images,其中包含Id 108 ..不只是一个!

      这是一个简单的项目,只需几行代码即可对其进行测试:

      test project

1 个答案:

答案 0 :(得分:1)

正如您在评论中所写,多对多关系表在两个FK键上都定义了PK,因此不可能将两次相同的组合放在一起。我首先考虑一下你的商业模式是否真的可以实现这种情况。如果它应该,那么你可以采用的一种方法是手动声明你的中间表并给它人工PK(例如,只是自动增加int)。

然后在EF中,您将拥有两个一对多关系(从Symbol和从Image到中级表,您可以调用任何内容 - 例如ImagesInSymbol左右。 使用这些集合将不太方便但可行。作为奖励,您稍后可以在此关系上设置其他属性(例如DateCreatedStatus等)。

有关详细信息,请参阅此question