2011-08-26 61 views
0

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

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方法,并将其传递到一个包含语句。思考?

回答

13

我已经在我的代码做了这样的事情最近。以下是否适合你?

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 => e.Prop1, e=> e.Prop2, e=> e.Prop3);

我知道这并不完全按照你的方式,但我认为按要求,你可以重构它。

+0

完美!谢谢 – DDiVita

+0

@Paige:我试过使用这段代码,但是当我追踪SQL时,没有一个包含实际添加(但是懒加载可能会导致错觉)。但是,如果我硬编码相同包括成一行** var set = _unitOfWork.CreateSet ().include(includeProperties [0]); **然后包含出现在SQL中。因此,在分别编写Includes时,看起来类型上有些不同,这些我还没有完成。 – Appetere

+0

现在就开始工作 - 需要对代码进行一些更改。我用我使用的代码添加了一个新答案。 – Appetere

0

的方法,包括可以在LINQ查询串在一起,像这样:

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

我明白,但是这并没有回答我的问题。在我的服务层中,我想传递给存储库,但是在我的服务层中没有实际编写链接包含时可以包含哪些内容。那我可以把它传递给某种包含构建器的东西? – DDiVita

+0

我不确定它是否可以工作,但你可以传递一串字符串,这将是关系属性,然后循环遍历它们,构建你的IQueryable。 Jay

+0

它想到了这一点。我将尝试并更新我的问题。另一种选择是扩展包含方法? – DDiVita

8

我不认为佩奇库克的代码将非常努力,如图所示。

我已经包含代码的修改版本,应该改为工作:

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); 
} 

我只看准了这一点通过跟踪由实体框架生成的SQL,并实现了原代码仅是给的错觉工作,通过使用延迟加载来填充指定包含的实体。

实际上,有用于applying the Include statements using the LINQ Aggregate method一个更简洁的语法,这是链接到博客文章。我的文章还通过退回Find方法稍微改进了方法,当不需要包含时,还显示了如何使用类似语法实现“GetAll”方法的示例。

+0

史蒂夫,我不明白这和我的回答有什么不同?代码看起来和我完全一样。您的GetAll方法丢失。你确定你发布了正确的代码片段吗? –

+3

@PaigeCook有两个区别。首先,你必须使用Include语句的返回值。原始代码只是说** set.Include(includeProperty); **但我认为这必须是** set = set.Include(includeProperty); **。第二个变化是我发现我必须明确声明“set”为IQueryable ,而不是使用“var”。使用您的原始代码,您是否跟踪了SQL - 如果它工作正常,我很感兴趣!我文章的最后一段描述了我的博客文章中的内容,其中包括GetAll方法和terser LINQ版本。 – Appetere

+0

对于任何正在寻找“terse语法”引用的博客帖子的更新链接的朋友,请登录http://appetere.com/post/passing-include-statements-into-a-repository – Patrick

0

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

我修改史蒂夫的代码,并得到这个对我的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; 
    }