我有一个计数器,用于计算视图的显示次数:
public class News
{
[Key]
public int Id { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DatePostedOn { get; set; }
public DateTime DateModified { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Meta { get; set; }
public string UrlSlug { get; set; }
public bool Popular { get; set; }
public int Position { get; set; }
public int Views { get; set; } // <---- COUNTER
}
每次加载页面时,我都会看到+1:
public virtual ActionResult Detail(string urlSlug)
{
News news = db.News
.Include("Category")
.Where(n => n.UrlSlug.Equals(urlSlug))
.FirstOrDefault();
NewsDetailVM vm = Mapper.Map<News, NewsDetailVM>(news);
vm.RelatedNews = db.News
.Where(r => r.Category.Id == news.Category.Id)
.Where(r => r.Hidden == false)
.Where(r => r.Id != news.Id)
.OrderByDescending(r => r.DateCreated)
.Take(3)
.Select(r => new NewsRelatedVM()
{
Title = r.Title,
Date = r.DateCreated,
UrlSlug = r.UrlSlug,
CategoryName = r.Category.Name,
CategoryURLSlug = r.Category.UrlSlug,
PictureURL = r.Pictures.Where(p => p.Type == 2).FirstOrDefault().Filename
})
.ToList();
vm.CategoriesList = db.Categories
.Where(c => c.Channel == 1)
.Project().To<NewsListCategoryItemVM>()
.ToList();
news.Views = news.Views + 1; // <-- COUNTER UPDATE
db.SaveChanges();
return View(vm);
}
问题在于,例如在星期六,当天发布的新闻有6464,Google分析为新闻控制器提供了2359次综合浏览量。
从哪里出现这种差异?我在柜台上做错了吗?
答案 0 :(得分:7)
几乎不可能说出这种差异的确切原因是什么,但也有一些可能的罪魁祸首。首先,GA可能会忽略机器人,特别是GoogleBot。但是,您的方法并不会将机器人索引到您的网站。例如,每次GoogleBot点击此视图时,它都会在数据库中递增,但不会在GA中递增。您需要通过蜘蛛将此视图排除在访问之外,或者找一些方法来过滤掉机器人的请求。
其次,GA可能会过滤掉重复的匹配。例如,假设用户登陆视图,然后点击刷新按钮50次。您的数据库计数增加了50倍,但GA可能仍将其视为单个网页浏览。一般情况下,您应该通过记录REMOTE_IP来限制您的计数器,并且只有在该IP在一段时间内(例如15分钟)没有访问该页面时才会增加。然后,你至少不会记录每次刷新。
最后,在这种情况下,计数将始终处于关闭状态,因为并非每个客户端都支持或启用了JavaScript(意味着GA无法跟踪这些客户端),并且客户端的隐私设置也可能会阻止GA跟踪。然而,无论您是否愿意,此数据库计数都将计算每个请求。
答案 1 :(得分:3)
您不能依赖Entity Framework来更新这样的计数器,因为它会将最新值提取到内存中,在内存中更改它,然后将其保存到数据库中。
如果有多个人同时点击你的动作方法,那么他们每个人都可以将相同的值增加1并将其保存回数据库。在更新数据库时,您需要对数据库中的值执行锁定。
或者允许数据库执行它最擅长的操作,即管理更新 像这样,您可以通过使用存储过程来实现这一点,例如我刚刚在下面编写的那个:
CREATE PROCEDURE usp_increment_count (@newsId int)
UPDATE dbo.News SET Views = Views + 1 WHERE id = @newsId
GO
然后使用实体框架从代码中调用该过程:
SqlParameter newsId = new SqlParameter("@newsId", news.Id);
db.Database.ExecuteSqlCommand("usp_increment_count @newsId", newsId);
我希望这会有所帮助。
答案 2 :(得分:2)
计数不是完全相同的,也不是100%准确。
如果有并发访问,您的实体框架代码将不起作用。见Concurrency with EF。本文向您展示了如何修改表和程序以使计数准确。具有存储过程的解决方案看起来可以与您的示例一起使用,但不是一般解决方案,因为除非在存储过程中完成所有更改,否则它也将失败。这在EF6中更容易。
Google Analytics(分析)有一系列问题。有很多文章提供详细信息,这里是sample article。不要在客户端代码中折扣编码问题。
您可能考虑的解决方案是创建一个新表来跟踪访问。这很容易解决EF并发问题。新表行至少包含主键和新闻Id列。只需在每次读取时添加一个新行。然后使用单独的查询访问计数,使用适当的索引,这应该足够快。这种方法的优点是您可以添加额外的信息,如访问时间,访问来源以及协调或证明您的计数所需的任何其他信息。
您可能尝试帮助解决问题的另一件事是分析Web服务器日志。有很多选项,维基百科是一个很好的起点,搜索“网络服务器日志分析”。同样,这些测量的东西略有不同,并且会给出不同的计数。