这让我在过去的3个小时里难过......我可能只是累了但似乎无法让逻辑正确。我想做的是;
所有主题一次提供1个,每次主题评级,保存后我将其重定向回该控制器。
我认为我的string.equals不起作用,但似乎无法找出原因。控制器只是继续提供相同的主题。 (我假设它的第一个记录与那个不匹配的记录相匹配?)
public ActionResult Index(string page)
{
Rating rating = new Rating();
var surveyItems = (from s in db.Surveys
where s.Category.Name.Equals(page)
select s).ToList();
var ratedItems = (from r in db.Ratings
where r.Category.Equals(page) && r.UserName.Equals(User.Identity.Name)
select r).ToList();
if (ratedItems.Count() == 0 && surveyItems.Count() > 0)
{
ViewBag.Remaining = surveyItems.Count();
rating.Topic = surveyItems.Select(si => si.Topic).FirstOrDefault();
rating.Category = page;
return View(rating);
}
else if (ratedItems.Count() > 0 && ratedItems.Count() == surveyItems.Count())
{
return View("Finished");
}
else
{
foreach (var si in surveyItems)
{
foreach (var ri in ratedItems)
{
if (!si.Topic.Equals(ri.Topic))
{
rating.Topic = si.Topic;
rating.Category = page;
ViewBag.Total = surveyItems.Count();
ViewBag.Remaining = ViewBag.Total - ratedItems.Count();
return View(rating);
}
}
}
}
答案 0 :(得分:1)
首先,要直接回答您的问题,您的内部循环将始终失败,因为2个列表未被排序 AND 并且没有保证每个列表中的项目1将是相同的。即使它们是,第一个列表中的第二个项目也不会等于第二个列表中的第一个项目(内部循环)。
最好的办法是完全使用LINQ解决这个问题,虽然查询有点难以理解,但代码更清晰。
var rating = (from s in db.Surveys
join r in db.Ratingson s.Topic equals r.Topic into rated
from ri in rated.Where(x => x.Username == User.Identity.Name).DefaultIfEmpty()
where s.Category.Name.Equals(page) && ri.Topic == null
select new RatingViewModel {Topic = s.Topic, Category = s.Category, Total = db.SurveyItems.Count(), Rated = rated.Count()}).FirstOrDefault();
if (rating == null)
{
return View("Finished");
}
return View(rating);
LINQ查询本质上等同于以下SQL(给出或接受)
SELECT * FROM Surveys s
LEFT OUTER JOIN Ratings r ON s.Topic = r.Topic AND r.Username = 'user'
WHERE r.Topic IS NULL
您还会注意到查询投放到RatingsViewModel
,我添加了这个,因为我注意到您对ViewBag
以及Rating
实体有一些引用。< / p>
RatingViewModel:
public class RatingViewModel
{
public string Topic { get; set; }
public string Category { get; set; }
public int Total { get; set; }
public int Rated { get; set; }
public int Remaining {
get { return Total - Rated; }
}
}
修改强>
更多地使用查询,这是我能得到的最接近的:
// define the where's here so we can use the IQueryable multiple times in LINQ
var surveys = db.Surveys.Where(x => x.Category.Name.Equals(page));
var ratedItems = db.Ratings.Where(y => y.Username == User.Identity.Name && y.Category.Name.Equals(page));
var rated = ratedItems.Count(); // get the rated count here, otherwise we end up with an exception inside the LINQ query
var surveyTopic =
(from s in surveys
// LEFT OUTER JOIN to ratings
join r in ratedItems on s.Topic equals r.Topic into ratedSurveys
from ri in ratedSurveys.DefaultIfEmpty()
// define variables
let total = surveys.Count()
//let rated = ratedItems.Count() -- this throws a NotSupportedException... which seems odd considering the line above
// get non-rated surveys, in this case the RIGHT side of the join (Ratings) is null if there is no rating
where ri.Topic == null
// projection
select new RatingViewModel
{
Topic = s.Topic,
Category = s.Category,
Rated = rated,
Total = total
}).FirstOrDefault();
return surveyTopic == null ? View("Finished") : View(surveyTopic);
不幸的是,这导致我希望避免的2个DB查询,但这应该更接近你所追求的。
答案 1 :(得分:0)
布伦特,
它不喜欢你的解决方案,所以我试着稍微修改它但它仍然不开心。这是我的调整;
var surveyTopic = (from s in db.Surveys.Where(x => x.Category.Name.Equals(page))
let total = s.Topic.Count()
join r in db.Ratings.Where(y => y.UserName == User.Identity.Name) on s.Topic equals r.Topic
let rated = r.Topic.Count()
where r.Topic == null
select new RatingViewModel
{
Topic = s.Topic,
Category = s.Category.Name,
Rated = rated+1,
Total = total
}).FirstOrDefault();