实体框架在运行时包含多个 [英] Entity Framework Multiple Include at runtime

查看:37
本文介绍了实体框架在运行时包含多个的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个传递参数的服务,该参数要包含多少导航属性.基于布尔args,它连接一个实体列表以包括每个必需的外部实体.

I have a service that passes in parameters for how much I want to include for navigation properties. Based upon the boolean args it concatenates an entity list to include each required foreign entity.

在运行时,我不希望包含导航实体,也可以不包含多个导航实体.我不能做的是使用 .Include().Include 进行菊花链连接,因为我不知道传入的args包含哪些以及包含多少个.

At runtime I want to include either no navigation entities or many. What I can't do is daisy chain with .Include().Include as I don't know which and how many to include based around passed in args.

我想实现这一目标,但似乎无法传递以逗号分隔的实体列表.有什么想法吗?

I want to achieve this, but I don't seem to be able to pass in a comma separated entity list. Any ideas?

var res = db.Entity.Include(entityListCommaSeparated).Where(_=>_.ID == ID).FirstOrDefault();

推荐答案

这看起来像一个存储库模式,如果要尝试从调用代码中隐藏" EF/DbContext,通常会变得混乱.

This looks like a repository pattern, and generally gets messy if you want to try and "hide" EF / the DbContext from calling code.

您可以考虑以下几种选择:

A couple options you can consider:

  1. 降低复杂性的麻烦:在适用的存储库方法中使用 params Expression< Func< TEntity,object>>>>>> ,然后准备也传递OrderBy表达式当您要返回多个实体时作为分页值.
  2. 通过简单镜像:将IQueryable用作返回类型,并让消费者根据需要处理Includes,OrderBy,Counts/Any/Skip/Take/First/ToList和 .Select()
  1. Down the complexity rabit hole: use a params Expression<Func<TEntity, object>>[] includes in your applicable repository methods, and then be prepared to also pass OrderBy expressions, as well as pagination values when you want to return multiple entities.
  2. THrough the simplicity mirror: Embrace IQueryable as a return type and let the consumers handle Includes, OrderBy's, Counts/Any/Skip/Take/First/ToList, and .Select() as they need.

选项1:

public Order GetById(int id, params Expression<Func<Order, object>>[] includes)
{
     var query = db.Orders.Where(x => x.ID == id);
     // This part can be moved into an extension method or a base repository method.
     if(includes.Any)  
        includes.Aggregate(query, (current, include) => 
        {
            current.Include(include);
        }
     // Don't use .FirstOrDefault() If you intend for 1 record to be returned, use .Single(). If it really is optional to find, .SingleOrDefault()
     return query.Single();
}
//ToDo
public IEnumerable<Order> GetOrders(/* criteria?, includes?, order by?, (ascending/descending) pagination? */)
{ }
// or
public IEnumerable<Order> GetOrdersByCustomer(/* includes?, order by?, (ascending/descending) pagination? */)
{ }
// plus..
public IEnumerable<Order> GetOrdersByDate(/* includes?, order by?, (ascending/descending) pagination? */)
{ }
public bool CustomerHasOrders(int customerId)
{ }
public bool OrderExists(int id)
{ }
public int OrdersOnDate(DateTime date)
{ }
// etc. etc. etc.

请记住,这不能处理自定义order by子句,对于返回实体列表的方法,也需要同样的处理.您的存储库还需要公开 .Any()(DoesExist)的方法,因为每个人喜欢每次返回都检查#null.:)也是 .Count().

Keep in mind this doesn't handle custom order by clauses, and the same will be needed for methods that are returning lists of entities. Your repository is also going to need to expose methods for .Any() (DoesExist) because everyone loves checking for #null on every return. :) Also .Count().

选项2:

public IQueryable<Order> GetById(int id)
{
    return db.Orders.Where(x => x.ID == id);
}
public IQueryable<Order> GetOrders()
{
    return db.Orders.AsQueryable();
}

呼叫者可以在调用 .Single()之前查看Linq和 .Include()他们想要的内容,或者执行 .Any()..他们可能不需要整个实体图,因此可以从实体和相关实体中进行 .Select(),而无需 .Include()来组成和执行更有效的查询来填充ViewModel/DTO.GetById可能在许多地方使用,因此我们可以减少重复并在存储库中支持它.我们不需要所有的筛选器方案等,调用者可以调用GetOrders,然后根据需要进行筛选.

Callers can grok Linq and .Include() what they want before calling .Single(), or do a .Any().. They may not need the entire entity graph so they can .Select() from the entity and related entities without .Include() to compose and execute a more efficient query to populate a ViewModel / DTO. GetById might be used in a number of places so we can reduce duplication and support it in the repository. We don't need all of the filter scenarios etc, callers can call GetOrders and then filter as they see fit.

如果仅返回DBSet,为什么还要为存储库而烦恼?

Why bother with a repository if it just returns DBSets?

  1. 集中进行低级数据过滤.例如,如果您使用软删除(IsActive)或正在运行多租户或显式授权.这些通用规则可以集中在存储库级别,而不必在接触DbSet的任何地方都记住.
  2. 测试更简单.虽然可以模拟DbContext或将其指向内存数据库,但模拟返回IQueryable的存储库更为简单.(只需填充 List< TEntity> 并返回 .AsQueryable().
  3. 存储库处理创建和删除.创建以用作工厂,以确保为可行的实体建立所有必需的数据和关系.删除以处理软删除方案,级联/审核等,超出数据库在后台处理的范围.

这篇关于实体框架在运行时包含多个的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆