簡體   English   中英

多對多關系-實體框架

[英]Many to Many Relation - Entity Framework

我正在與多對多關系進行工作,基本上是:

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

表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)

您指定兩個不同的DbContext, RedesDAOObjetivosDAO 兩個對象的EntityFramework上下文是不同的,這意味着您的第二個上下文無法看到該對象是從數據庫中獲取的。

要修復,可以替換以下行:

Objetivos Objetivo = ObjetivosDAO.ObtemPorId(ObjetivoID);

與:

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

這樣可以防止將對象誤認為是新對象。


附帶說明一下,除非有特定的原因將它們分開,否則最好使用單個DbContext類與數據庫進行通信。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM