情况草图
我开发了一个系统,其中可以将许多材料(代码为Matetiaal
)添加到广告中(代码为Zoeker
)。这种关系是多对多的。在这里,您了解了我的课程结构。
+-------------------------------------+ many to many +-------------------------------+
| Zoeker | <--------------> | Materiaal |
+------------+------------------------+ +---------+---------------------+
| ID | int | | ID | int |
| Materialen | ICollection<Materiaal> | | Zoekers | ICollection<Zoeker> |
| Titel | string | | Naam | string |
+------------+------------------------+ +---------+---------------------+
我将使用下一个伪代码添加新的材料和广告:
void Insert(Zoeker zoeker, string[] materialen)
{
foreach (string m in materialen)
{
Materiaal mat = materiaalRepo.GetByName(m);
if (mat == null)
{
mat = materiaalRepo.Insert(new Materiaal(m));
}
zoeker.Materialen.Add(mat);
}
zoekerRepo.Insert(zoeker);
}
换句话说,当必须添加新广告(
Zoeker
)时,我将检查数据库中是否已存在该材料。如果材质不存在,则方法materialenRepo.GetByName(string)
返回null
。如果是这样,则将新材料插入数据库并返回Materiaal
对象。之后,或者如果materialenRepo.GetByName(string)
没有返回null
,则将该材料添加到广告的Materialen
属性中,然后将其插入数据库中。要将数据库与我的应用程序连接,我使用实体框架。
我的问题
当我使用下面标题中的代码时,出现了此异常:
System.InvalidOperationException
:多个IEntityChangeTracker
实例不能引用实体对象。public virtual TEntity Insert(TEntity entity)
{
return dbSet.Add(entity); // <-- on this line
}
调用
zoekerRepo.Insert(zoeker);
时,将在标记的行上引发异常。我的密码
在这里您可以找到我编写的代码。
服务
public class ZoekService
{
public int InsertZoeker(Zoeker zoeker, ApplicationUser user, string materialenString)
{
return InsertZoeker(zoeker, user, materialenString.Split(','));
}
public int InsertZoeker(Zoeker zoeker, ApplicationUser user, string[] materialen)
{
zoeker.Gebruiker = user;
zoeker.Materialen = new List<Materiaal>();
using (ApplicationDbContext ctx = new ApplicationDbContext())
{
ZoekerRepository zoekerRepo = new ZoekerRepository(ctx);
MateriaalRepository materiaalRepo = new MateriaalRepository(ctx);
// ^^^^ See update one
foreach (string m in materialen)
{
Materiaal materiaal = materiaalRepo.GetByNaam(m);
if (materiaal == null)
{
materiaal = materiaalRepo.Insert(new Materiaal(m));
// ^ See update three
}
zoeker.Materialen.Add(materiaal);
}
zoekerRepo.Insert(zoeker);
zoekerRepo.SaveChanges(); // <-- Pointer didn't come on this line.
return zoeker.ID;
}
}
}
储存库
ZoekerRepository
扩展GenericRepository<Zoeker>
public class ZoekerRepository : GenericRepository<Zoeker>
{
public ZoekerRepository()
{ }
public ZoekerRepository(ApplicationDbContext ctx): base(ctx)
{ }
// Some other methods I've add or will override.
}
MateriaalRepository
扩展GenericRepository<Materiaal>
public class MateriaalRepository : GenericRepository<Materiaal>
{
public MateriaalRepository()
{ }
public MateriaalRepository(ApplicationDbContext ctx): base(ctx)
{ }
public Materiaal GetByNaam(string naam)
{
return (from m in dbSet
where m.Naam.Equals(naam)
select m).SingleOrDefault<Materiaal>();
}
// Some other methods I've add or will override.
}
GenericRepository<TEntity>
public class GenericRepo<TEntity> where TEntity : class
{
internal ApplicationDbContext context;
internal DbSet<TEntity> dbSet;
public GenericRepo()
{
context = new ApplicationDbContext();
dbSet = context.Set<TEntity>();
}
public GenericRepo(ApplicationDbContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual TEntity Insert(TEntity entity)
{
return dbSet.Add(entity); // <-- after `zoekerRepo.Insert(Zoeker)` the exception
// will be thrown on this line.
}
public void SaveChanges()
{
try
{
context.SaveChanges();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
我做了什么
当然,我尝试了其他代码,但是所有代码都给出了相同的异常。我将编写代码,以便使用相同的名为
GenericRepo<TEntity>
的通用类将材料的存储库与广告存储库与广告存储库分离(除了我将添加或覆盖的东西之外)。我将尽可能地重用它。一次用于GenericRepo<Zoeker>
,另一次用于GenericRepo<Materiaal>
。我的问题
我该如何解决这个错误?
更新一个
此问题与entity object cannot be referenced by multiple instances of IEntityChangeTracker. while adding related objects to entity in Entity Framework 4.1重复,因为我使用的上下文与接受的答案相同:
您可以通过在服务类之外创建上下文并在两个服务中注入和使用它来解决此问题:
EmployeeService es = new EmployeeService(context);
CityService cs = new CityService(context); // same context instance
请参阅上面的代码注释。
更新两个
在这里,您已经完成了我编写的代码的新部分。
控制器
public class DeelController : Controller
{
private UserManager<ApplicationUser> UserManager { get; set; }
private ZoekService _zoekservice = new ZoekService();
public DeelController()
{
this.UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(ApplicationDbContext));
}
[HttpGet]
[Authorize]
public ActionResult Nieuw()
{
return View(new Zoeker());
}
[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Nieuw(Zoeker zoeker)
{
_zoekservice.InsertZoeker(zoeker, await UserManager.FindByNameAsync(User.Identity.Name), zoeker.MaterialenString);
return RedirectToAction(nameof(Index));
}
}
班级
Zoeker
扩展Post
public class Zoeker: Post
{
public virtual ICollection<Materiaal> Materialen { get; set; }
public virtual ICollection<ApplicationUser> Delers { get; set; }
[NotMapped]
public string MaterialenString { get; set; } // <-- contains a comma separated
// list of all materials
}
Post
public class Post
{
[Key]
public int ID { get; set; }
public string Titel { get; set; }
public string Omschrijving { get; set; }
public virtual ApplicationUser Gebruiker { get; set; }
public string GebruikerID { get; set; }
public DateTime StartPeriode { get; set; }
public DateTime? Verwijderd { get; private set; }
public DateTime? Opgelost { get; private set; }
public DateTime? Belangerijk { get; private set; }
public virtual ICollection<Antwoord> Antwoorden { get; set; }
}
更新三
我也尝试用此代码替换上面代码中的注释行,但没有解决此错误:
materiaal = /*materiaalRepo.Insert(*/ new Materiaal(m); //);
如果我使用的材料不存在,请使用更新3的代码,那么我会再次遇到该错误。
更新四
如果使用观察者,则会看到以下内容:
Material[0]
的字段_entityWrapper
类型为EntityWrapperWithoutRelationships<System.Data.Entity.DynamicProxies.Materiaal_E0DDEFDA63D33C75C64324662B40FDC414EC19CA4AD6BF18443B63FC60015374>
。注意:该材料在数据库中已经存在。同样在这里,我有同样的错误。更新五
我还替换了`InsertZoeker(Zoeker
public int InsertZoeker(Zoeker zoeker, ApplicationUser user, string[] materialen)
{
Zoeker newZoeker = new Zoeker()
{
Gebruiker = user,
StartPeriode = DateTime.Now,
Materialen = new List<Materiaal>(),
Titel = zoeker.Titel,
Omschrijving = zoeker.Omschrijving
};
using (ApplicationDbContext ctx = new ApplicationDbContext())
{
ZoekerRepository zoekerRepo = new ZoekerRepository(ctx);
MateriaalRepository materiaalRepo = new MateriaalRepository(ctx);
foreach (string m in materialen)
{
Materiaal materiaal = materiaalRepo.GetMateriaalByNaam(m);
if (materiaal == null)
{
materiaal = /*materiaalRepo.Insert(*/ new Materiaal(m); //);
}
newZoeker.Materialen.Add(materiaal);
}
zoekerRepo.Insert(newZoeker);
zoekerRepo.SaveChanges();
return zoeker.ID;
}
}
最佳答案
对我而言,我很愚蠢,我正在使用其他上下文将用户吸引到我的DeelController
中。我已在问题中删除了该代码。
@mjwills:确实是一个重复的问题。
@everyone_else:对不起,我已经做到了。
关于c# - 如何将两个不同的对象插入数据库,但检查它们是否已存在,则抛出`InvalidOperationException`?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44780506/