简体   繁体   English

多对多关系-实体框架

[英]Many to Many Relation - Entity Framework

I'm working with a many to many relation, basically: 我正在与多对多关系进行工作,基本上是:

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

Table Objetivos is a set of previously registered options. 表Objetivos是一组先前注册的选项。 When my user tries to register a new Redes, he chooses among a list of Objetivos and save. 当我的用户尝试注册新的Redes时,他在Objetivos列表中进行选择并保存。

At this moment Objetivos table has 8 options 目前,Objetivos表有8个选项

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

Lets suppose I include a new Redes and select Objetivos 5 to 8 The final result currently is: 假设我包括一个新的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       |
                +---+---------------+

The result I want is: 我想要的结果是:

+-------------+ +-------------------+ +---------------------------+
|    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       |
                +---+---------------+   

Basically, EF is not identifying that Objetivos already exists in the database and is creating new rows. 基本上,EF不会识别Objetivos是否已存在于数据库中并正在创建新行。 How can I correctly indicate to EF that those Objetivos are already there ? 我如何正确地向EF指示那些Objetivos已经存在?

I went through a lot of search on how to work with many to many with EF and I know that there are questions that are similar to mine, but since I could not solve my problem with them, I decided to post my whole scenario in order to get help. 我进行了很多搜索,以了解如何与EF进行多对多协作,我知道有些问题与我的相似,但是由于无法解决它们的问题,我决定按顺序发布整个方案获得帮助。

This is what I have at the moment: 这是我目前所拥有的:

//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; }
    }

Note that the method I execute in order to save a new Redes is the override that is on the RedesDAO class. 请注意,为了保存新的Redes而执行的方法是RedesDAO类上的重写。

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

You specify 2 different DbContexts, RedesDAO and ObjetivosDAO . 您指定两个不同的DbContext, RedesDAOObjetivosDAO The context of the EntityFramework is different for both objects, meaning that your second context cannot see that the object is taken from the database. 两个对象的EntityFramework上下文是不同的,这意味着您的第二个上下文无法看到该对象是从数据库中获取的。

To fix, you can replace the following line: 要修复,可以替换以下行:

Objetivos Objetivo = ObjetivosDAO.ObtemPorId(ObjetivoID);

with: 与:

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

This should prevent the objects from being mistaken for new. 这样可以防止将对象误认为是新对象。


As a sidenote, unless you have a specific reason for separating them, it might be better to use a single DbContext class for communicating with your database. 附带说明一下,除非有特定的原因将它们分开,否则最好使用单个DbContext类与数据库进行通信。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM