首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用存储库模式使用ThenIclude加载实体

使用存储库模式使用ThenIclude加载实体
EN

Stack Overflow用户
提问于 2016-05-26 06:06:23
回答 2查看 6.9K关注 0票数 15

我的应用程序使用实体框架7和存储库模式。

存储库上的GetById方法支持急切地加载子实体:

代码语言:javascript
运行
AI代码解释
复制
public virtual TEntity GetById(int id, params Expression<Func<TEntity, object>>[] paths)
{
    var result = this.Set.Include(paths.First());
    foreach (var path in paths.Skip(1))
    {
        result = result.Include(path);
    }
    return result.FirstOrDefault(e => e.Id == id);
}

使用如下方法检索产品(其id为2)以及与该产品相关的订单和部件:

代码语言:javascript
运行
AI代码解释
复制
productRepository.GetById(2, p => p.Orders, p => p.Parts);

我希望增强此方法,以支持嵌套在一个以上级别以上的实体的急切加载。例如,假设一个Order有自己的LineItem集合。

在EF7之前,我相信以下内容也可以检索与每个订单相关联的LineItems:

代码语言:javascript
运行
AI代码解释
复制
productRepository.GetById(2, p => p.Orders.Select(o => o.LineItems), p => p.Parts);

但是,在EF7中似乎不支持这一点。相反,有一个新的ThenInclude方法检索嵌套实体的其他级别:

https://github.com/aspnet/EntityFramework/wiki/Design-Meeting-Notes:-January-8,-2015

我不确定如何更新我的存储库,以支持使用ThenInclude检索多个级别的加载实体。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-05-11 17:50:41

这是个老生常谈的问题,但由于没有一个被接受的答案,我想我应该把我的解决方案发出来。

我正在使用eager,并且想要这样做,从我的存储库类外部访问急切的加载,这样我就可以在每次调用存储库方法时指定要加载的导航属性。因为我有大量的表和数据,所以我不想要一组标准的急切加载实体,因为我的一些查询只需要父实体,还有一些需要整棵树。

我目前的实现只支持IQueryable方法(即。FirstOrDefaultWhere,基本上是标准的lambda函数),但我确信您可以使用它传递到特定的存储库方法。

我从EF的EntityFrameworkQueryableExtensions.cs源代码开始,这是定义IncludeThenInclude扩展方法的地方。不幸的是,EF使用内部类IncludableQueryable来保存以前属性的树,以允许稍后进行强类型的包含。但是,这方面的实现只不过是为前一个实体提供了一个额外的泛型类型的IQueryable

我创建了自己的版本,名为IncludableJoin,它以IIncludableQueryable作为构造函数参数,并将其存储在私有字段中供以后访问:

代码语言:javascript
运行
AI代码解释
复制
public interface IIncludableJoin<out TEntity, out TProperty> : IQueryable<TEntity>
{
}

public class IncludableJoin<TEntity, TPreviousProperty> : IIncludableJoin<TEntity, TPreviousProperty>
{
    private readonly IIncludableQueryable<TEntity, TPreviousProperty> _query;

    public IncludableJoin(IIncludableQueryable<TEntity, TPreviousProperty> query)
    {
        _query = query;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public IEnumerator<TEntity> GetEnumerator()
    {
        return _query.GetEnumerator();
    }

    public Expression Expression => _query.Expression;
    public Type ElementType => _query.ElementType;
    public IQueryProvider Provider => _query.Provider;

    internal IIncludableQueryable<TEntity, TPreviousProperty> GetQuery()
    {
        return _query;
    }
}

注意内部GetQuery方法。这以后就很重要了。

接下来,在我的通用IRepository接口中,我定义了急切加载的起点:

代码语言:javascript
运行
AI代码解释
复制
public interface IRepository<TEntity> where TEntity : class
{
    IIncludableJoin<TEntity, TProperty> Join<TProperty>(Expression<Func<TEntity, TProperty>> navigationProperty);
    ...
}

TEntity泛型类型是我的EF实体的接口Join方法在我的泛型存储库中的实现如下所示:

代码语言:javascript
运行
AI代码解释
复制
public abstract class SecureRepository<TInterface, TEntity> : IRepository<TInterface>
    where TEntity : class, new()
    where TInterface : class
{
    protected DbSet<TEntity> DbSet;
    protected SecureRepository(DataContext dataContext)
    {
        DbSet = dataContext.Set<TEntity>();
    }

    public virtual IIncludableJoin<TInterface, TProperty> Join<TProperty>(Expression<Func<TInterface, TProperty>> navigationProperty)
    {
        return ((IQueryable<TInterface>)DbSet).Join(navigationProperty);
    }
    ...
}

现在,对于实际允许多个IncludeThenInclude的部分。我有几个接受并返回的扩展方法和允许方法链接的IIncludableJoin。在其中,我在Include上调用EF、ThenInclude和DbSet方法:

代码语言:javascript
运行
AI代码解释
复制
public static class RepositoryExtensions
{
    public static IIncludableJoin<TEntity, TProperty> Join<TEntity, TProperty>(
        this IQueryable<TEntity> query,
        Expression<Func<TEntity, TProperty>> propToExpand)
        where TEntity : class
    {
        return new IncludableJoin<TEntity, TProperty>(query.Include(propToExpand));
    }

    public static IIncludableJoin<TEntity, TProperty> ThenJoin<TEntity, TPreviousProperty, TProperty>(
         this IIncludableJoin<TEntity, TPreviousProperty> query,
         Expression<Func<TPreviousProperty, TProperty>> propToExpand)
        where TEntity : class
    {
        IIncludableQueryable<TEntity, TPreviousProperty> queryable = ((IncludableJoin<TEntity, TPreviousProperty>)query).GetQuery();
        return new IncludableJoin<TEntity, TProperty>(queryable.ThenInclude(propToExpand));
    }

    public static IIncludableJoin<TEntity, TProperty> ThenJoin<TEntity, TPreviousProperty, TProperty>(
        this IIncludableJoin<TEntity, IEnumerable<TPreviousProperty>> query,
        Expression<Func<TPreviousProperty, TProperty>> propToExpand)
        where TEntity : class
    {
        var queryable = ((IncludableJoin<TEntity, IEnumerable<TPreviousProperty>>)query).GetQuery();
        var include = queryable.ThenInclude(propToExpand);
        return new IncludableJoin<TEntity, TProperty>(include);
    }
}

在这些方法中,我使用前面提到的IIncludableQueryable方法获得内部GetQuery属性,调用相关的IncludeThenInclude方法,然后返回一个新的IncludableJoin对象来支持方法链接。

就是这样。它的用法如下:

代码语言:javascript
运行
AI代码解释
复制
IAccount account = _accountRepository.Join(x=>x.Subscription).Join(x=>x.Addresses).ThenJoin(x=>x.Address).FirstOrDefault(x => x.UserId == userId);

上面将加载基本的Account实体,它是一对一的子Subscription,它是一对多的子列表Addresses,它是子Address。整个过程中的每个lambda函数都是强类型的,并且得到intellisense的支持,以显示每个实体上可用的属性。

票数 14
EN

Stack Overflow用户

发布于 2016-05-26 07:47:07

您可以将其更改为以下内容:

代码语言:javascript
运行
AI代码解释
复制
public virtual TEntity GetById<TEntity>(int id, Func<IQueryable<TEntity>, IQueryable<TEntity>> func) 
{
    DbSet<TEntity> result = this.Set<TEntity>();

    IQueryable<TEntity> resultWithEagerLoading = func(result);

    return resultWithEagerLoading.FirstOrDefault(e => e.Id == id);
}

你可以这样用它:

代码语言:javascript
运行
AI代码解释
复制
productRepository.GetById(2, x => x.Include(p => p.Orders)
                                   .ThenInclude(o => o.LineItems)
                                   .Include(p => p.Parts))
票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37463226

复制
相关文章
EF Code First 学习笔记:关系
项目中最常用到的就是一对多关系了。Code First对一对多关系也有着很好的支持。很多情况下我们都不需要特意的去配置,Code First就能通过一些引用属性、导航属性等检测到模型之间的关系,自动为我们生成外键。观察下面的类:
跟着阿笨一起玩NET
2018/09/19
7760
EF Code First 学习笔记:关系
WCF Data Services 5.0 和 EF 4.3 Code First
WCF Data Services 5.0已经在4月9日发布,支持OData V3版本的协议。之前版本的WCF Data Services是随.NET FX 4.0发布的,这次是单独提供了安装包下载。这个版本有几个特性很不错,具体参看文章 http://blogs.msdn.com/b/writingdata_services/archive/2012/04/09/my-favorite-things-in-odata-v3-and-wcf-data-services-5-0.aspx。 新特性主要用于支持
张善友
2018/01/29
9050
(转载)EF 使用code first模式创建数据库和 填充种子数据
第一篇:来自 .net 开发菜鸟 博主的文章:https://www.cnblogs.com/dotnet261010/p/8035213.html
CherishTheYouth
2019/09/11
8750
EF 数据库连接约定(Connection String Conventions in Code First)
一个典型的EF应用大多数情况下是一个DbContext的派生类(derived class)来控制,通常可以使用该派生类调用DbContext的构造函数,来控制以下的东西: (1)、上下文如何连接到数据库(给定连接字符串) (2)、上下文是通过Code First语法计算模型还是使用EF 设计器 (3)、额外的高级选项 下面是DbContext构造器的常用的用途: 一、DbContext无参构造函数 如果当前EF应用中没有做任何的配置.且在你自定义的数据库上下文类中没有调用DbContext带参的构造函数,
郑小超.
2018/01/26
1.5K0
MVC Code First (代码优先)
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/116945.html原文链接:https://javaforall.cn
全栈程序员站长
2022/07/06
9400
MVC Code First (代码优先)
VS2010+EF Code First 4.1学习MVC3(三)
htmlHelper 和UrlHelper 类,这是我们在View层进行页面显示组件的常用类或者是唯一类,但是我们又对它了解哪些呢?我们了解为什么可以使用htmlHelper类?因为使用了扩展方法,我们自己是否可以正确的定义一些helper类来满足我们自己的业务需求,对于扩展方法我们又理解多少?htmlHelper类中的那几个方法我们是否完全的掌握?
Isaac Zhang
2019/09/10
4760
VS2010+EF Code First 4.1学习MVC3(三)
VS2010+EF Code First 4.1学习MVC3(一)
这里的环境只有VS2010,EF CF4.1,继续加入Jquery EasyUI,做一个用户列表(选中,编辑,删除,新增)
Isaac Zhang
2019/09/10
5080
VS2010+EF Code First 4.1学习MVC3(一)
VS2010+EF Code First 4.1学习MVC3(二)
在MVC中,Area使我们的业务逻辑更加清晰,为我们后期的维护带来了极大的便利,那么今天我就来啃啃这一块的东西,可以很方便的替代UrlRouting的一些功能哦~~
Isaac Zhang
2019/09/10
4470
VS2010+EF Code First 4.1学习MVC3(二)
Entity Framework Code-First 文章汇集
为了支持以设计为中心的开发流程,EF4 还更多地支持以代码为中心 (code-centric) ,我们称为代码优先的开发,代码优先的开发支持更加优美的开发流程,它允许你: 在不使用设计器或者定义一个 XML 映射文件的情况下进行开发。 允许编写简单的模型对象POCO (plain old classes),而不需要基类。 通过"约定优于配置",使得数据库持久层不需要任何的配置 也可以覆盖"约定优于配置",通过流畅的 API 来完全定制持层的映射。 使用Code first这个模式后,你的项目中可以说就不再需
张善友
2018/01/30
8000
关于EF Code First模式不同建模方式对建表产生的影响
今天在学EF Code First模式的时候,发现几个很有趣的问题,问题如下: 1、当编写玩实体后,不指定任何主键约束,EF会找长的最像Id的,然后设置其为主键,验证代码如下: //User类 class User { public Guid UserId { get; set; } public string Name { get; set; } } class CodeFirstContext:DbContext {
郑小超.
2018/01/26
1K0
【原】尝试 Entity Framework POCO功能+Code First
Entity Framework 2.0中添加了的支持POCO(Plain Old CLR Object)的功能,这使得EF的功能越来越强大了。
老马
2022/05/10
5760
【原】尝试 Entity Framework POCO功能+Code First
Entity Framework 4.1 Code-First 学习笔记
  CodeFirst提供了一种先从代码开始工作,并根据代码直接生成数据库的工作方式。Entity Framework 4.1在你的实体不派生自任何基类、不添加任何特性的时候正常的附加数据库。另外呢,实体的属性也可以添加一些标签,但这些标签不是必须的。下面是一个简单的示例:
拓荒者IT
2019/09/25
1.7K0
Entity Framework Code First 支持存储过程
存储过程(Stored Procedure)不仅仅是将多得简直荒唐的业务逻辑塞入数据库的一种方式;它还是避免将多得简直荒唐的存储逻辑塞入应用程序层(application layer)的一种方式。它使得应用程序可被视为理想的数据表现,同时又不会泄露数据库管理员(DBA)的神机妙算。各种各样的暂存表、非规范化的报告表、视图、以及表函数都被隐藏在简单的存储过程调用背后,从而形成了数据库的公共应用编程接口(API)。注意,从微小的性能调整到全面重构的一切都可以完成,且无须重新部署许许多多依赖于该数据库的应用程序。
张善友
2018/01/30
5770
Entity Framework应用:使用Code First模式管理数据库创建和填充种子数据
在数据库上下文类中,如果我们只继承了无参数的DbContext,并且在配置文件中创建了和数据库上下文类同名的连接字符串,那么EF会使用该连接字符串自动计算出数据库的位置和数据库名。比如,我们的数据库上下文定义如下:
CherishTheYouth
2019/09/11
1.3K0
Entity Framework应用:使用Code First模式管理数据库创建和填充种子数据
创建自己的Code Snippets在VSCode中
1. Go to Code → Preferences → User Snippets
前端知否
2020/03/23
2.8K0
创建自己的Code Snippets在VSCode中
RAM IP Core中 Write First Read First和No Change的区别
可能很多人都没注意过这个选项,记得毕业季去华为面试的时候,还问过我这个问题,当时也是没答上来。后来也发现很多面试官都喜欢问这个问题,今天我们就来讲一下。
猫叔Rex
2020/06/29
1.3K0
在 Visual Studio Code (VS Code) 中设置
在 Visual Studio Code (VS Code) 中设置代理服务器的详细教程如下:
用户614136809
2023/10/25
1.5K0
EF Core使用CodeFirst在MySql中创建新数据库以及已有的Mysql数据库如何使用DB First生成域模型
官方教程:https://docs.microsoft.com/en-us/aspnet/core/data/?view=aspnetcore-2.1 使用EF CodeFirst在MySql中创建新
Ryan_OVO
2023/10/19
5600
laravel 中first和find区别(总结一)
除了从指定的数据表检索所有记录外,你也可以通过 find 或 first 方法来检索单条记录。这些方法不是返回一组模型,而是返回一个模型实例:
全栈程序员站长
2022/07/08
8920
Coroutines : First things first
该系列博客深入探索了协程的取消和异常。取消 可以避免进行预期以外的工作,从而节省内存和电量;合适的异常处理 可以带来良好的用户体验。作为该系列另外两篇文章的基础,通过本文搞清楚协程的一些基本概念,例如 CoroutineScope 、Job 、CoroutineContext 等,是非常重要的。
路遥TM
2021/08/31
6680

相似问题

EF Code First DBContext和事务

131

EF Code First -删除后播种,然后创建数据库

31

EF Code first部署脚本

20

EF Code first父子映射

10

EF Code first DropCreateDatabaseIfModelChanges部署

13
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档