多对多关系 - 实体框架

时间:2018-02-04 16:53:40

标签: c# entity-framework entity-framework-6

我正在处理多种关系,基本上是:

+-------------+ +-----------------+ +---------------------------+
|    Redes    | |    Objetivos    | |       RedesObjetivos      |
+-------------+ +-----------------+ +---------------------------+
|   | RedesID | |   | ObjetivosID | |   | RedesID | ObjetivosID |
+---+---------+ +-----------------+ +---------------------------+
| 1 |         | | 1 |             | | 1 |         |             |
+---+---------+ +-----------------+ +---------------------------+

Table Objetivos是一组先前注册的选项。当我的用户尝试注册新的Redes时,他会在Objetivos列表中选择并保存。

此时Objetivos表有8个选项

+------------------+
|     Objetivos    |
+------------------+
|    | ObjetivosID |
+----+-------------+
| 1  |      1      |
+----+-------------+
| 2  |      2      |
+----+-------------+
| 3  |      3      |
+----+-------------+
| 4  |      4      |
+----+-------------+
| 5  |      5      |
+----+-------------+
| 6  |      6      |
+----+-------------+
| 7  |      7      |
+----+-------------+
| 8  |      8      |
+----+-------------+

假设我添加了一个新的Redes并选择了Objetivos 5到8 目前的最终结果是:

+-------------+ +-------------------+ +---------------------------+
|    Redes    | |     Objetivos     | |       RedesObjetivos      |
+-------------+ +-------------------+ +---------------------------+
|   | RedesID | |   | ObjetivosID   | |   | RedesID | ObjetivosID |
+---+---------+ +---+---------------+ +---------------------------+
| 1 |    1    | | 1 |      1        | | 1 |    1    |      9      |
+---+---------+ +---+---------------+ +---------------------------+
                | 2 |      2        | | 2 |    1    |      10     |
                +---+---------------+ +---------------------------+
                | 3 |      3        | | 3 |    1    |      11     |
                +---+---------------+ +---------------------------+
                | 4 |      4        | | 4 |    1    |      12     |
                +---+---------------+ +---------------------------+
                | 5 |      5        |
                +---+---------------+
                | 6 |      6        |
                +---+---------------+
                | 7 |      7        |
                +---+---------------+
                | 8 |      8        |
                +---+---------------+
                | 9 |      9        |
                +---+---------------+
                | 10|      10       |
                +---+---------------+
                | 11|      11       |
                +---+---------------+
                | 12|      12       |
                +---+---------------+

我想要的结果是:

+-------------+ +-------------------+ +---------------------------+
|    Redes    | |     Objetivos     | |       RedesObjetivos      |
+-------------+ +-------------------+ +---------------------------+
|   | RedesID | |   |  ObjetivosID  | |   | RedesID | ObjetivosID |
+---+---------+ +---+---------------+ +---------------------------+
| 1 |    1    | | 1 |       1       | | 1 |    1    |      5      |
+---+---------+ +---+---------------+ +---------------------------+
                | 2 |       2       | | 2 |    1    |      6      |
                +---+---------------+ +---------------------------+
                | 3 |       3       | | 3 |    1    |      7      |
                +---+---------------+ +---------------------------+
                | 4 |       4       | | 4 |    1    |      8      |
                +---+---------------+ +---------------------------+
                | 5 |       5       |
                +---+---------------+
                | 6 |       6       |
                +---+---------------+
                | 7 |       7       |
                +---+---------------+
                | 8 |       8       |
                +---+---------------+   

基本上,EF并未确定Objetivos已存在于数据库中并且正在创建新行。我怎样才能正确地向EF表明那些Objetivos已经存在?

我经历了很多关于如何与EF一起工作的搜索,我知道有类似于我的问题,但由于我无法解决他们的问题,我决定发布我的全部场景以获得帮助。

这就是我现在所拥有的:

//DAL Layer

//Interface where a set the basic database methods
public interface IDao<T> where T : class
{
    //Save
    int Salva(T Modelo);
    //Update
    int Atualiza(T model);
    //Delete
    void Exclui(T model);
    //GetAll
    IEnumerable<T> ObtemTodos();
    //GetByID
    T ObtemPorId(object id);
    IEnumerable<T> Where(Expression<Func<T, bool>> expression);
    IEnumerable<T> OrderBy(Expression<System.Func<T, bool>> expression);
}

//Generic context, where i implement the methods in the interface
public partial class dbContext<T> : DbContext where T : class
    {
        public DbSet<T> DbSet
        {
            get;
            set;
        }

        public dbContext()
            : base("name=dbContext")
        {
        }

        public virtual void ChangeObjectState(object model, EntityState state)
        {
            ((IObjectContextAdapter)this)
                            .ObjectContext
                            .ObjectStateManager
                            .ChangeObjectState(model, state);
        }

        //Save
        public virtual int Salva(T model)
        {
            this.DbSet.Add(model);
            return this.SaveChanges();
        }
        //Update
        public virtual int Atualiza(T model)
        {
            var entry = this.Entry(model);

            if (entry.State == EntityState.Detached)
                this.DbSet.Attach(model);

            this.ChangeObjectState(model, EntityState.Modified);
            return this.SaveChanges();
        }
        //Delete
        public virtual void Exclui(T model)
        {
            var entry = this.Entry(model);

            if (entry.State == EntityState.Detached)
                this.DbSet.Attach(model);

            this.ChangeObjectState(model, EntityState.Deleted);
            this.SaveChanges();
        }
        //GetAll
        public virtual IEnumerable<T> ObtemTodos()
        {
            return this.DbSet.ToList();
        }
        //GetByID
        public virtual T ObtemPorId(object id)
        {
            return this.DbSet.Find(id);
        }

        public virtual IEnumerable<T> Where(Expression<Func<T, bool>> expression)
        {
            return this.DbSet.Where(expression);
        }

        public IEnumerable<T> OrderBy(Expression<Func<T, bool>> expression)
        {
            return this.DbSet.OrderBy(expression);
        }
    }

//Then the relevant DAO classes where I implement specific database methods if necessary
public class RedesDAO : dbContext<Redes>, IDao<Redes>
    {
        //Save
        public override int Salva(Redes Model)
        {
            ObjetivosDAO ObjetivosDAO = new ObjetivosDAO();
            Model.RedeObjetivos = new List<Objetivos>();

            //ObjetivosSelecionados is a List<int> with Ids that relates to user's selected options on my view
            //each option relates to an especific Objetivos row that already exist in the database
            foreach (int ObjetivoID in Model.ObjetivosSelecionados)
            {
                //So, with each ID I obtain the whole information for that entity
                //by using the ObtemPorId = GetByID method and adding it to models' collection
                Objetivos Objetivo = ObjetivosDAO.ObtemPorId(ObjetivoID);
                Model.RedeObjetivos.Add(Objetivo);                
            }

            this.DbSet.Add(Model);
            return this.SaveChanges();
        }        

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Redes>().
              HasMany(c => c.RedeObjetivos).
              WithMany(p => p.Redes).
              Map(
               m =>
               {
                   m.MapLeftKey("RedeID");
                   m.MapRightKey("ObjetivoID");
                   m.ToTable("RedesObjetivos");
               });
        }
    }

public class ObjetivosDAO : dbContext<Objetivos>, IDao<Objetivos>
    {
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Objetivos>().
              HasMany(c => c.Redes).
              WithMany(p => p.RedeObjetivos).
              Map(
               m =>
               {
                   m.MapLeftKey("ObjetivoID");
                   m.MapRightKey("RedeID");
                   m.ToTable("RedesObjetivos");
               });
        }
    }   

//And my models/tables
public partial class Redes
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int RedeID { get; set; }
        [Required]
        public ICollection<Objetivos> RedeObjetivos { get; set; }
        [NotMapped]
        public List<int> ObjetivosSelecionados { get; set; }        
    }

public partial class Objetivos
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int ObjetivoID { get; set; }
        [Required]
        public ICollection<Redes> Redes { get; set; }
    }

请注意,我为保存新Redes而执行的方法是RedesDAO类的覆盖。

//Model = Information that comes from my view
public override int Salva(Redes Model)

1 个答案:

答案 0 :(得分:0)

您指定了2个不同的DbContexts,RedesDAOObjetivosDAO。 EntityFramework的上下文对于两个对象都是不同的,这意味着您的第二个上下文无法看到该对象是从数据库中获取的。

要修复,您可以替换以下行:

Objetivos Objetivo = ObjetivosDAO.ObtemPorId(ObjetivoID);

使用:

Objetivos Objetivo = base.Set<Objetivos>().Find(ObjetivoID);

这可以防止对象被误认为是新的。

作为旁注,除非您有特定的理由将它们分开,否则最好使用单个DbContext类与数据库进行通信。