持久实体框架嵌套/相关实体

本文关键字:实体 框架 嵌套 | 更新日期: 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();
        }
    }