I have the following function:
public List<DTO.ArticleDTO> GetRecentArticles(int portalID, int moduleID, int domainID, int rootKnowledgeTypeID, int count)
{
var articles =
(from
article in _Context.Articles.LatestArticles(_Context.ArticleVersions, portalID, moduleID)
where _GetRootDomainsForArticle(article.ArticleID, article.Version, rootKnowledgeTypeID).Contains(domainID)
orderby article.UpdatedOn descending
select new ArticleDTO
{
ArticleID = article.ArticleID,
Title = article.Title,
Summary = article.Introduction,
Content = article.Content,
UpdatedOn = article.UpdatedOn,
Version = article.Version,
KnowledgeTypeText = (from
category in _Context.Categories
join
categoryVersion in _Context.ArticleCategoryVersions
on
category.CategoryID equals categoryVersion.CategoryID
where
categoryVersion.Version == article.Version &&
categoryVersion.ArticleID == article.ArticleID &&
category.ParentID == rootKnowledgeTypeID
select
category.Name
).First()
});
return articles.Take(count).ToList();
}
What I'm trying to do is get all the articles that belong to a root category (domain ID). Categories are considered to be Domains/SubDomains and each article can belong to one or more Domains and Sub Domains. So this is why I used the following method in the where clause of the above linq query.
private IQueryable<int> _GetRootDomainsForArticle(int articleID, int version, int rootKnowledgeTypeID)
{
return from c in _Context.Categories
join cv in _Context.ArticleCategoryVersions on c.CategoryID equals cv.CategoryID
where cv.ArticleID == articleID
where cv.Version == version
where c.ParentID == null
where c.CategoryID != rootKnowledgeTypeID
select c.CategoryID;
}
The error I get is: "Comparison operators not supported for type 'System.Linq.IQueryable`1[System.Int32]'."
I think is is because of deferred execution, but I don't quite understand the right way to do it.
Edit:
Based on @SivaGopal comment I moved the query from the _GetRootDomainsForArticle to become part of the main query and it worked:
public List<DTO.ArticleDTO> GetRecentArticles(int portalID, int moduleID, int domainID, int rootKnowledgeTypeID, int count)
{
var articles =
(from
article in _Context.Articles.LatestArticles(_Context.ArticleVersions, portalID, moduleID)
where (from c in _Context.Categories
join cv in _Context.ArticleCategoryVersions on c.CategoryID equals cv.CategoryID
where cv.ArticleID == article.ArticleID
where cv.Version == article.Version
where c.ParentID == null
where c.CategoryID != rootKnowledgeTypeID
select c.CategoryID).Contains(domainID)
orderby article.UpdatedOn descending
select new ArticleDTO
{
ArticleID = article.ArticleID,
Title = article.Title,
Summary = article.Introduction,
Content = article.Content,
UpdatedOn = article.UpdatedOn,
Version = article.Version,
KnowledgeTypeText = (from
category in _Context.Categories
join
categoryVersion in _Context.ArticleCategoryVersions
on
category.CategoryID equals categoryVersion.CategoryID
where
categoryVersion.Version == article.Version &&
categoryVersion.ArticleID == article.ArticleID &&
category.ParentID == rootKnowledgeTypeID
select
category.Name
).First()
});
return articles.Take(count).ToList();
}
My limited understanding of Linq lead me to believe that one could split that query out to a method as form of query composition and in so doing making it reusable. Seems not to be the case, but surely there must be a way to do this as it would drastically reduce code especially where portions of queries are reused quite often.
Try splitting up your function more, the long and deep Linq method can work, but it is not that good for readability purposes and can introduce these sort of bugs that you are talking about. I haven't tested this yet but it should help solve your issue:
public List<DTO.ArticleDTO> GetRecentArticles(int portalID, int moduleID, int domainID, int rootKnowledgeTypeID, int count)
{
var allArticles = _Context.Articles.LatestArticles(_Context.ArticleVersions, portalID, moduleID);
var filteredArticles = new List<DTO.ArticleDTO>();
foreach (DTO.ArticleDTO article in allArticles)
{
var domains = _GetRootDomainsForArticle(article.ArticleID, article.Version, rootKnowledgeTypeID);
if (domains.Contains(domainID)
{
filteredArticles.Add(article);
}
}
var articles = filteredArticles.OrderBy(article.UpdatedOn).Descending().Select(article => new DTO.ArticleDTO {
ArticleID = article.ArticleID,
Title = article.Title,
Summary = article.Introduction,
Content = article.Content,
UpdatedOn = article.UpdatedOn,
Version = article.Version,
KnowledgeTypeText = (from category in _Context.Categories
join categoryVersion in _Context.ArticleCategoryVersions
on category.CategoryID equals categoryVersion.CategoryID
where
categoryVersion.Version == article.Version &&
categoryVersion.ArticleID == article.ArticleID &&
category.ParentID == rootKnowledgeTypeID
select
category.Name
).First()
}).Take(count).ToList();
}
Also do you absolutely need to return IQueryable<> from your _GetRootDomainsForArticle function? If you can get away with it, I'd try returning IEnumerable<> instead.
Koda
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.