联盟对空可数

时间:2015-04-29 06:16:30

标签: c# linq entity-framework

我有功能

public async Task<IQueryable<Document>> GetDocuments(...)

我在某些特定条件下搜索文档。某些条件可以跳过。最后,我执行这些查询的联合。

   var documents = await documentService.GetDocuments(this, userId,
                roleShowFullNumber, param.OrderColName(), param.SearchValue, filter);
  var usersGroupsId = filter.UsersGroupsId;
        if (usersGroupsId != null)
        {
            if (!usersGroupsId.Contains("All"))
            {
                IQueryable<Document> myDocs = Enumerable.Empty<Document>().AsQueryable();
                if (usersGroupsId.Contains("myOrders"))
                {
                    myDocs = documents.Where(x => x.OwnerId == userId || x.UserId == userId);
                    usersGroupsId = usersGroupsId.Where(x => x != "myOrders").ToArray();
                }
                IQueryable<Document> wards = Enumerable.Empty<Document>().AsQueryable();
                if (usersGroupsId.Contains("wards"))
                {
                    var relatedUserId = _db.Users.Where(x => x.Id == userId).Select(x => x.RelatedUserId).FirstOrDefault();
                    if (relatedUserId != null)
                    {
                        var myWards = _db.kh__Kontrahent.Where(x => x.kh_IdOpiekun == relatedUserId);
                        var myWardsUsers = _db.Users.Where(x => myWards.Any(w => w.kh_Id == (x.RelatedCustomerId == null ? -1 : x.RelatedCustomerId)));
                        wards = documents.Where(x => (myWardsUsers.Any(w => x.UserId == w.Id) || myWardsUsers.Any(w => x.OwnerId == w.Id)));
                        usersGroupsId = usersGroupsId.Where(x => x != "wards").ToArray();
                    }
                }

                IQueryable<Document> groups = Enumerable.Empty<Document>().AsQueryable();
                if (usersGroupsId.Length > 0)
                {
                    var usersGroups = _db.Groups.Where(x => usersGroupsId.Contains(x.Id.ToString()));
                    var usersList = usersGroups.Select(x => x.Users);
                    var users = usersList.SelectMany(x => x);
                    var usersId = users.Select(x => x.Id);
                    groups = _db.Documents.Where(x => (usersId.Any(u => u == x.OwnerId) || usersId.Any(u => u == x.UserId)));
                }

                documents = myDocs.Union(wards).Union(groups);

            }
        }

但是当我尝试以下面显示的方式获取这些文档时,如果其中一个部分查询为空(被跳过),则会出错。

   var documentsPaginated = await documents.Skip(param.Start)
                                    .Take(param.Length)
                                    .ToListAsync();

错误:源IQueryable未实现IDbAsyncEnumerable。

如何使此功能能够跳过一些子查询然后联合所有。我宁愿不改变函数返回值。

2 个答案:

答案 0 :(得分:1)

试试这个,虽然你的代码似乎有大量的代码味道......

public async Task<IQueryable<Document>> GetDocuments(...)      
   var documents = await documentService.GetDocuments(this, userId,
                roleShowFullNumber, param.OrderColName(), param.SearchValue, filter);
  var usersGroupsId = filter.UsersGroupsId;
        if (usersGroupsId != null)
        {
            if (!usersGroupsId.Contains("All"))
            {
                IQueryable<Document> myDocs = null;
                if (usersGroupsId.Contains("myOrders"))
                {
                    myDocs = documents.Where(x => x.OwnerId == userId || x.UserId == userId);
                    usersGroupsId = usersGroupsId.Where(x => x != "myOrders").ToArray();
                }
                IQueryable<Document> wards = null;
                if (usersGroupsId.Contains("wards"))
                {
                    var relatedUserId = _db.Users.Where(x => x.Id == userId).Select(x => x.RelatedUserId).FirstOrDefault();
                    if (relatedUserId != null)
                    {
                        var myWards = _db.kh__Kontrahent.Where(x => x.kh_IdOpiekun == relatedUserId);
                        var myWardsUsers = _db.Users.Where(x => myWards.Any(w => w.kh_Id == (x.RelatedCustomerId == null ? -1 : x.RelatedCustomerId)));
                        wards = documents.Where(x => (myWardsUsers.Any(w => x.UserId == w.Id) || myWardsUsers.Any(w => x.OwnerId == w.Id)));
                        usersGroupsId = usersGroupsId.Where(x => x != "wards").ToArray();
                    }
                }

                IQueryable<Document> groups = null;
                if (usersGroupsId.Length > 0)
                {
                    var usersGroups = _db.Groups.Where(x => usersGroupsId.Contains(x.Id.ToString()));
                    var usersList = usersGroups.Select(x => x.Users);
                    var users = usersList.SelectMany(x => x);
                    var usersId = users.Select(x => x.Id);
                    groups = _db.Documents.Where(x => (usersId.Any(u => u == x.OwnerId) || usersId.Any(u => u == x.UserId)));
                }
                if(myDocs != null)
                    documents = documents.Union(myDocs);
                if(wards != null)
                    documents = documents.Union(wards);
                if(groups != null)
                    documents = documents.Union(groups);

            }
        }

答案 1 :(得分:0)

似乎ToListAsync不能与linq互换使用,只能在EF查询中使用。

来自MSDN

  

Entity Framework 6引入了一组可用于异步执行查询的扩展方法。这些方法的示例包括ToListAsync,FirstAsync,ForEachAsync等。

     

由于Entity Framework查询使用LINQ,因此扩展方法在IQueryable和IEnumerable上定义。但是,因为它们仅用于与Entity Framework一起使用,所以如果您尝试在不是实体框架查询的LINQ查询上使用它们,则可能会收到以下错误。

     

源IQueryable没有实现IDbAsyncEnumerable {0}。只有实现IDbAsyncEnumerable的源才能用于Entity Framework异步操作。有关详细信息,请参阅http://go.microsoft.com/fwlink/?LinkId=287068