[英]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,
RedesDAO
和ObjetivosDAO
。 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.