使用skip并进入LINQ include

时间:2016-12-24 13:12:49

标签: c# linq

我有一个具有属性的对象,该属性是另一个对象的集合。我想使用LINQ加载集合属性的一个子集。

以下是我尝试这样做的方法:

manager = db.Managers
            .Include(m => m.Transactions.Skip((page - 1) * 10).Take(10))
            .Where(m => m.Id == id)
            .FirstOrDefault();

上面的代码会抛出一个错误

  

Include路径表达式必须引用在类型上定义的导航属性。使用虚线路径作为参考导航属性,使用Select运算符作为集合导航属性。\ r \ n参数名称:路径

在LINQ中执行此操作的正确方法是什么?提前谢谢。

2 个答案:

答案 0 :(得分:1)

您不能使用Include执行此操作。 EF根本不知道如何将其转换为SQL。但你可以用子查询做类似的事情。

final String path = "http://localhost:8080/RestEasy-Spring-MVC-Hibernate/";
ICustomerService proxy = null;

    @Before
    public void beforeClass(){
        ResteasyClient client = new ResteasyClientBuilder().build();
        ResteasyWebTarget target = client.target(UriBuilder.fromPath(path));
        proxy = target.proxy(ICustomerService.class);
    }

@Test
    public void testCustomerByIdNewAPI() throws Exception{  
        CustomerType customerType = proxy.getCustomerInfo(1);
        System.out.println("----------------------------------------------------");
        System.out.println("Name       : "+customerType.getName());
        System.out.println("Age        : "+customerType.getAge());
        System.out.println("CustomerId : "+customerType.getCustomerId());
    }

这不会返回Manager类的实例。但是应该很容易修改它以满足您的需求。

您还有两个选择:

  1. 加载所有交易,然后在内存中过滤。当然,如果有很多交易,这可能效率很低。
  2. 不要害怕在数据库中进行2次查询。这是最好的例子,这可能是最好的路线,并且可能是最有效的方式。
  3. 无论哪种方式,如果你完全关注性能,我会建议你测试所有3种方法,看看哪种方法最快。请告诉我们结果如何!

答案 1 :(得分:0)

有时,将所有内容放在一个查询中的额外复杂性是不值得的。我会把它分成两个单独的查询:

var manager = db.Managers.SingleOrDefault(m => m.Id == id);
var transactions = db.Transactions
    .Where(t => t.ManagerId == id)
    // .OrderBy(...)
    .Skip((page - 1) * 10).Take(10)
    .ToList();

请注意,执行此操作后,还可以使用manager.Transactions来引用那些刚刚加载的事务:只要将加载的实体加载到同一个上下文中,它就会自动链接它们。只需确保禁用延迟加载,以防止EF自动拉入您专门尝试过滤掉的所有其他事务。