持久实体框架嵌套/相关实体
本文关键字:实体 框架 嵌套 | 更新日期: 2023-09-27 18:13:18
我有以下实体:
public class ModuleCriteria
{
public int ModuleCriteriaId { get; set; }
public string Criteria { get; set; }
public List<ModuleCriteriaLookup> ModuleCriteriaLookups { get; set;
}
}
public class ModuleCriteriaLookup
{
public int ModuleCriteriaLookupId { get; set; }
public int ModuleCriteriaId { get; set; } // ** (Foreign Key) **
public int SiteId { get; set; }
public string CategoryId { get; set; }
public ModuleCriteria ModuleCriteria { get; set; }
}
我在Context
类中有以下EF配置(为简洁而编辑):
protected override void OnModelCreating( DbModelBuilder modelBuilder )
{
base.OnModelCreating( modelBuilder );
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<ModuleCriteriaLookup>().HasRequired( mc => mc.ModuleCriteria );
// I tried adding the below line but it made no difference.
//modelBuilder.Entity<ModuleCriteria>().HasMany( mc => mc.ModuleCriteriaLookups );
}
…并且我在Context
类中定义了以下DbSet
属性:
public DbSet<ModuleCriteria> ModuleCriteria { get; set; }
public DbSet<ModuleCriteriaLookup> ModuleCriteriaLookup { get; set; }
我有一个CriteriaRepository
类,它有一个Save
方法,用于持久更改我的ModuleCriteria
实体:
public void Save( ModuleCriteria moduleCriteria )
{
using ( var ctx = new MyAppContext() )
{
ctx.Entry( moduleCriteria ).State = moduleCriteria.ModuleCriteriaId == 0 ? EntityState.Added : EntityState.Modified;
ctx.SaveChanges();
}
}
一个ModuleCriteria
对象可以在没有ModuleCriteriaLookup
对象的情况下存在,但ModuleCriteriaLookup
对象必须与一个现有的ModuleCriteria
对象相关(在ModuleCriteriaId
上相关)。
你可以有多个ModuleCriteraLookup
对象都与同一个ModuleCriteria
对象相关。
我希望并期望EF的行为是:
1)如果我创建一个新的ModuleCriteria
对象(没有任何ModuleCriteriaLookups
),在我的存储库中调用Save
方法,我希望在db中看到新的ModuleCriteria
记录,而在db中没有相关的ModuleCriteriaLookup
记录。
2)如果我创建一个新的ModuleCriteria
对象并分配一个List<ModuleCriteriaLookup>
给它,在我的存储库中调用Save方法,我希望在db中看到新的ModuleCriteria
记录和db中与特定ModuleCriteria
相关的x个新的ModuleCriteriaLookup
行。
3)如果我添加/编辑/删除任何与我的ModuleCriteria
对象相关的ModuleCriteriaLookup
对象,然后在我的存储库中调用Save
方法,我希望看到任何ModuleCriteria
删除的ModuleCriteriaLookup
对象从db中删除,任何新添加的和任何编辑的对象只是为了更新。
所以我所需要担心的是,无论ModuleCriteria.ModuleCriteriaLookups
属性包含给定的ModuleCriteria
,这将反映在我的DB中的2个表中,只需调用存储库中ModuleCriteria
对象的Save方法。
不幸的是,目前,如果我添加一个新的ModuleCriteria
对象与相关的List<ModuleCriteriaLookup>
它添加ModuleCriteria
和x ModuleCriteriaLookup
行在db很好。但是,当我想编辑或删除ModuleCriteria.ModuleCriteriaLookups
属性中的条目时,这并没有反映在数据库中。ModuleCriteriaLookups
行没有任何变化。
我不确定问题到底在哪里,是否它是否EF映射配置,或者与存储库如何工作有关?
问题位于存储库中。DbContext
需要知道实体的存在。因此,当编辑和/或删除实体时,需要首先从数据库中获取实体。
这个描述清楚地说明:
.Entry
属性从上下文返回对象由上下文跟踪。
因为在创建上下文之后直接使用了这个属性,所以上下文不会跟踪这些实体,因此不会意识到某些东西已经发生了变化。因此无法生成正确的SQL语句。
有几种方法可以处理这个问题,这取决于您设计的其余部分。删除它的一种方法是:
public void DeleteModuleCriteriaLookup(ModuleCriteriaLookup[] lookups)
{
using (var ctx = new MyAppContext())
{
var moduleCriteriaId = lookups.First().ModuleCriteriaId;
var moduleCritria = (
from criteria in ctx.ModuleCriteria
where criteria.ModuleCriteriaId == moduleCriteriaId
select criteria
).Single();
var lookupIdsToDelete = lookups.Select(l => l.ModuleCriteriaLookupId);
var lookupsToDelete = (
from lookup in moduleCritria.ModuleCriteriaLookups
where lookupIdsToDelete.Contains(lookup.ModuleCriteriaLookupId)
select lookup
).ToArray();
foreach (var lookup in lookupsToDelete)
{
moduleCritria.ModuleCriteriaLookups.Remove(lookup);
}
ctx.SaveChanges();
}
}