C# 实体框架父子表仅返回直接子表
我有一个标准的父/子EF模型,如下所示C# 实体框架父子表仅返回直接子表,c#,entity-framework,rest,asp.net-web-api2,C#,Entity Framework,Rest,Asp.net Web Api2,我有一个标准的父/子EF模型,如下所示 public class DataDictionary { public int Id { get; set; } public String Name { get; set; } public int? ParentId { get; set; } [JsonIgnore] public virtual DataDictionary Parent { get; set; } public virtu
public class DataDictionary
{
public int Id { get; set; }
public String Name { get; set; }
public int? ParentId { get; set; }
[JsonIgnore]
public virtual DataDictionary Parent { get; set; }
public virtual ICollection<DataDictionary> Children { get; set; }
}
但是,我只需要获取请求的对象和直接子对象,以便在用户浏览数据时,我的消费者可以建立可视化表示
更新:感谢大家的评论,所有这些看起来都很好,但是我正在努力解决。包括,因为我在一个异步方法中,查找返回了对象,而我丢失了上下文。i、 e
[ResponseType(typeof(DataDictionary))]
public async Task<IHttpActionResult> GetDataDictionary(int id)
{
DataDictionary dataDictionary = await db.DataDictionaries.FindAsync(id);
if (dataDictionary == null)
{
return NotFound();
}
return Ok(dataDictionary);
}
[ResponseType(typeof(DataDictionary))]
公共异步任务GetDataDictionary(int id)
{
DataDictionary DataDictionary=await db.DataDictionary.FindAsync(id);
if(dataDictionary==null)
{
返回NotFound();
}
返回Ok(数据字典);
}
如果您不想检索孔子列表,请删除virtual关键字,我们将非常感谢您的帮助
并独立编程一个函数来加载第一个子项。对于您来说,这是因为实体中使用了“virtual”关键字。此关键字启用集合的延迟加载,所以当序列化程序序列化子集合时,它会尝试枚举此集合,从而导致从数据库加载它。之后,该集合中的每个元素都被递归序列化,从而导致从数据库加载每个子集合的负载(存在N+1选择问题) 要做你想做的事,你需要: 首先,从您的子属性中删除
virtual
关键字:
public class DataDictionary
{
public int Id { get; set; }
public String Name { get; set; }
public int? ParentId { get; set; }
[JsonIgnore]
public virtual DataDictionary Parent { get; set; }
public ICollection<DataDictionary> Children { get; set; }
}
公共类数据字典
{
公共int Id{get;set;}
公共字符串名称{get;set;}
public int?ParentId{get;set;}
[JsonIgnore]
公共虚拟数据字典父项{get;set;}
公共ICollection子项{get;set;}
}
其次,您需要急切地将此集合加载到控制器中。此代码将导致仅为dataDictionary类实例加载1个级别:
[ResponseType(typeof(DataDictionary))]
public async Task<IHttpActionResult> GetDataDictionary(int id)
{
DataDictionary dataDictionary = await db.DataDictionaries
.Include(x=>x.Children)
.FirstOrDefaultAsync(x=>x.Id == id);
if (dataDictionary == null)
{
return NotFound();
}
return Ok(dataDictionary);
}
[ResponseType(typeof(DataDictionary))]
公共异步任务GetDataDictionary(int id)
{
DataDictionary DataDictionary=等待db.DataDictionary
.包括(x=>x.儿童)
.FirstOrDefaultAsync(x=>x.Id==Id);
if(dataDictionary==null)
{
返回NotFound();
}
返回Ok(数据字典);
}
不要忘记在文件开头添加使用System.Data.Entity的,以访问.Include()
函数
也可以考虑,不要在API中使用实体框架实体——更好地创建DTOs,这将允许您对API结构有更少的依赖性,API -API只具有EF实体的一个子集字段。您还可以在这里限制树的深度,使子类没有子类集合
希望这有帮助 您可以禁用延迟加载,并仅对1个级别的子级执行快速加载。你能负担得起吗?是的,我能-我需要做什么才能触发仅1级的急切加载?我认为这样加载:dbContext.DataDictionaries.Include(x=>x.Children)代码>应该足够了,Include关键字是它被急切加载的原因。我认为现在当启用延迟加载时,序列化程序会遍历每个属性,导致lazy children集合的枚举,这会从DB中加载它们,并导致对每个孩子重复相同的过程,从而导致出现一个很好的旧N+1选择问题。感谢您的帮助-如Sergio所述,取消虚拟连接看起来不错,但是,我无法确定如何获得Include语句来填充子对象,因为我使用的是一个异步方法,该方法可以找到父对象,但我丢失了上下文。-请参阅更新的问题您能提供该方法的代码示例吗?谢谢Raderick-这正是我所需要的。同意你的紧耦合与松耦合的观点-我很懒:)很高兴这有帮助,@MarkRuse:)只是为了完整性,当我尝试上面的方法时,我从include链接得到了一个问题,因为它是可访问的,而不是DbSet(它有findAsync方法)。这解决了DataDictionary DataDictionary=await db.DataDictionary.Include(x=>x.Children.SingleOrDefaultAsync(i=>i.Id==Id)的问题@MarkRuse抱歉,我没有看到这一个,没有在ide中签入,你完全正确,我将相应地修改答案@MarkRuse还请记住,SingleOrDefault的效率可能低于FirstOrDefault,因为它会生成SELECT TOP 2
查询,而不是像FirstOrDefault那样只选择一个匹配项。
[ResponseType(typeof(DataDictionary))]
public async Task<IHttpActionResult> GetDataDictionary(int id)
{
DataDictionary dataDictionary = await db.DataDictionaries
.Include(x=>x.Children)
.FirstOrDefaultAsync(x=>x.Id == id);
if (dataDictionary == null)
{
return NotFound();
}
return Ok(dataDictionary);
}