【问题标题】:Passing multiple Include statements into a repository?将多个包含语句传递到存储库中?
【发布时间】:2011-08-26 15:25:29
【问题描述】:

我正在尝试找出一种方法将包含语句的集合传递到我的存储库中,以便我可以让它包含特定实体。以下是我的存储库中的一些示例代码。

   public TEntity GetById(Guid id)
        {
            return id != Guid.Empty ? GetSet().Find(id) : null;
        }
   private IDbSet<TEntity> GetSet()
            {
                return _unitOfWork.CreateSet<TEntity>();
            }

GetByID 方法调用 GetSet 以返回实体集。我在想,如果我能以某种方式传入一组实体以包含(通过表达式)作为我的 GetById 的一部分,这样我就不必将 GetSet 公开给我的服务。所以,是这样的:

var entity = _repository.GetById(theId, e => {e.Prop1, e.Prop2, e.Prop3});

然后我可以将该表达式传递给我的 GetSet 方法,并将它传递给一个包含语句。想法?

【问题讨论】:

    标签: entity-framework-4.1 linq-expressions


    【解决方案1】:

    我最近在我的代码中做了类似的事情。以下内容对您有用吗?

    public TEntity GetById(Guid id, params Expression<Func<TEntity, object>>[] includeProperties)
        {
            if (id == Guid.Empty) return null;
    
            var set = _unitOfWork.CreateSet<TEntity>();
            foreach(var includeProperty in includeProperties)
            {
                 set.Include(includeProperty);
            }
            return set.First(i => i.Id == id);
        }
    

    那你就这样称呼吧……

    var entity = _repository.GetById(theId, e =&gt; e.Prop1, e=&gt; e.Prop2, e=&gt; e.Prop3);

    我知道这并不完全符合您的模式,但我认为您可以根据需要对其进行重构。

    【讨论】:

    • @Paige:我尝试使用此代码,但是当我跟踪 SQL 时,实际上并没有添加任何包含(但延迟加载可能会给人一种错觉)。但是,如果我将相同的包含硬编码到一行 var set = _unitOfWork.CreateSet().Include(includeProperties[0]); 那么包含出现在 SQL 中。因此,在单独编写包含时,看起来类型有所不同,我还没有深入了解。
    • 现在可以工作了 - 需要对代码进行一些更改。我用我使用的代码添加了一个新答案。
    【解决方案2】:

    我认为 Paige Cook 的代码不会像所示的那样工作。

    我已经包含了应该可以工作的代码的修改版本:

    public TEntity GetById(Guid id, params Expression<Func<TEntity, object>>[] includeProperties)
    {
        if (id == Guid.Empty) return null;
    
        IQueryable<TEntity> set = _unitOfWork.CreateSet<TEntity>();
    
        foreach(var includeProperty in includeProperties)
        {
             set = set.Include(includeProperty);
        }
        return set.First(i => i.Id == id);
    }
    

    我只是通过跟踪 Entity Framework 生成的 SQL 发现了这一点,并意识到原始代码只是通过使用延迟加载来填充指定要包含的实体,从而给人一种工作的错觉。

    applying the Include statements using the LINQ Aggregate method 实际上有更简洁的语法,在链接到的博客文章中。我的帖子还通过在不需要包含时回退到 Find 方法来稍微改进该方法,并且还展示了如何使用类似语法实现“GetAll”方法的示例。

    【讨论】:

    • 史蒂夫,我看不出这与我的回答有何不同?代码看起来和我一模一样。并且您的 GetAll 方法丢失了。你确定你发布了正确的代码 sn-p 吗?
    • @PaigeCook 有两个不同之处。首先,您必须使用 Include 语句的返回值。原始代码只是说set.Include(includeProperty);,但我认为这必须是set = set.Include(includeProperty);。第二个变化是我发现我必须将“set”显式声明为 IQueryable 类型,而不是使用“var”。使用您的原始代码,您是否跟踪 SQL - 如果它有效,我很感兴趣!我文章的最后一段描述了我的博客文章中的内容,其中包括 GetAll 方法和更简洁的 LINQ 版本。
    • 对于任何寻找“简洁语法”appetere.com/post/passing-include-statements-into-a-repository 引用的博客文章的更新链接的人
    • 修复了帖子中的链接(并对我的重定向进行了排序,以便为原始链接添加书签的任何人)。感谢@Patrick 提醒我。
    【解决方案3】:

    出于多种原因,将上下文存储在非本地空间中是个坏主意。

    我修改了 Steve 的代码并将其用于我的 ASP.NET MVC 项目:

    public aspnet_User FirstElement(Func<aspnet_User, bool> predicate = null, params Expression<Func<aspnet_User, object>>[] includes)
        {
            aspnet_User result;
            using (var context = new DataContext())
            {
                try
                {
                    var set = context.Users.AsQueryable();
    
                    for (int i = 0; i < includes.Count(); i++ )
                        set = set.Include(includes[i]);
    
                    if (predicate != null)
                        result = set.ToList().FirstOrDefault(predicate);
                    else
                        result = set.ToList().FirstOrDefault();
                }
                catch
                {
                    result = null;
                }
            }
    
            return result;
        }
    

    【讨论】:

      【解决方案4】:

      include 方法可以像这样在您的 linq 查询中串在一起:

      var result = (from i in dbContext.TableName.Include("RelationProperty")
                                                 .Include("RelationProperty")
                                                 .Include("RelationProperty")
                      select i);
      

      【讨论】:

      • 我明白,但这并不能回答我的问题。在我的服务层中,我想将可以包含的内容传递给存储库,而无需在我的服务层中实际编写链接的包含。然后我可以将它传递给某种包含构建器?
      • 我不确定它是否会起作用,但您可以传递一组字符串,这将是关系属性,然后在您的 IQueryable 上循环遍历它们
      • 它想到了这一点。我将尝试并更新我的问题。另一种选择是扩展 Include 方法?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-24
      • 1970-01-01
      • 2015-03-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多