IList 在啥时候导致查询在 ORM 中执行?

Posted

技术标签:

【中文标题】IList 在啥时候导致查询在 ORM 中执行?【英文标题】:At what point does an IList cause a query to execute in an ORM?IList 在什么时候导致查询在 ORM 中执行? 【发布时间】:2013-03-12 12:04:53 【问题描述】:

我正在使用 Telerik 的 OpenAccess ORM,并且正在对生成的代码进行一些更改。对于具有导航属性(另一个表的键)的实体,这些属性会生成为 IList,如下所示:

private IList<SystemUser> _SystemUsers = new List<SystemUser>();
public virtual IList<SystemUser> SystemUsers 
 
    get
    
        return this._SystemUsers;
    

首先,SystemUsers 是在什么时候实际查询数据库的?它是一个 IList,所以我原以为这会在创建对象时针对数据库执行,但我知道事实并非如此。

我想要做的是过滤掉我所有生成的导航属性上的已删除项目,并且我一直在对 t4 模板进行更改以使用以下代码执行此操作:

private IList<SystemUser> _SystemUsers = new List<SystemUser>();

public virtual IList<SystemUser> SystemUsers 
 
    get
    
        if (!Entities.IncludeDeletedEntities)
        
            var currentContext = Entities.GetContext(this);
            ContextChanges changes = currentContext.GetChanges();
            IList<SystemUser> deletedItems = changes.GetDeletes<SystemUser>();
            return this._SystemUsers.Except(deletedItems).ToList(); //Question is here
        

        return this._SystemUsers;
    

本质上,这只是返回集合减去标记为删除的集合。我关心的是.ToList() 及其执行时间。我不想让ToList() 每次访问SystemUsers 时都查询数据库来减慢我的查询速度,但我也想过滤我的项目。我什至不确定ToList() 是否会导致数据库命中。我不确定代码何时会真正命中数据库,因此我正在寻找一些帮助/提示来过滤掉我已删除的项目而不使其命中数据库,直到我在代码中使用 SystemUsers 通过添加更多过滤器( where 子句等)。

【问题讨论】:

【参考方案1】:

我不能肯定地说 Telerik 工具,但我怀疑它们有点类似于 EF 和 LINQ to SQL,它们在调用 GetEnumerator(由 ToList 内部调用)时评估任何表达式。要自己进行测试,请使用分析工具来准确识别数据库请求的发出位置。 SQL Profiler 和 Intellitrace 应该适用于分析。还有其他可用的商业分析器,但我不确定 Telerik Open Access 有什么。您可能想查看他们的论坛。

【讨论】:

【参考方案2】:

我不了解 OpenAccess,但我认为大致相同的原则适用于实体框架。从那个背景来看,我只看到您的代码存在重大问题。

第一个反对意见是从架构的角度来看的。您的实体对象不应该知道上下文的存在。

其他反对意见是技术性的。

正如您已经指出的,您的代码将在每次处理 SystemUsers 时执行。 ToList() 总是会导致数据库命中。我不确定如果删除ToList() 会发生什么,这取决于GetChangesGetDeletes 的作用。我不知道。但至少每次枚举SystemUsers 时都会导致额外的数据库命中。

我假设,像 EF 一样,OpenAccess 也支持延迟加载标记为 virtual 的集合。可能它创建了一个从实体类型派生的代理类型,并为导航属性添加了连接以实现延迟加载。由于该属性只有一个吸气剂,我假设 OpenAccess 通过 Adding 向它填充一个集合。这会导致各种副作用:

    这意味着每次添加项目时都会访问(运行查询)基本属性。 您的代码返回一个临时列表。下次您处理该物业时,任何添加的项目都将消失!!集合永远不会被填充。

最后,当您的对象正在物化时打开第二个阅读器时,它可能会导致不可预知的行为。

所以我认为您应该通过一个存储库来解决软删除问题,该存储库返回带有或不带有标记为删除的实体的实体。或者,也许您可​​以创建一个计算的(未映射的)属性,该属性返回没有“已删除”的 SystemUsers。

【讨论】:

你提出了一些好观点。我想我会停止走这条危险的道路。

以上是关于IList 在啥时候导致查询在 ORM 中执行?的主要内容,如果未能解决你的问题,请参考以下文章

ORM增删改查

Entity Framework lambda 扩展方法在啥时候将查询发送到数据库?

orm的增删改查

这将在啥时候执行?

memcpy在啥情况下会失败

django的 ORM 操作 增加和查询