我遇到了一个奇怪的问题。当用户访问我的网络应用程序的任何页面时 我会检查用户是否有权访问它,并在第一次出现时提供试用期。
这是我的代码:
List<string> temp_workers_id = new List<string>();
...
if (temp_workers_id.Count > 6)
{
System.Data.SqlTypes.SqlDateTime sqlDate = new System.Data.SqlTypes.SqlDateTime(DateTime.Now.Date);
var rusers = dbctx.tblMappings.Where(tm => temp_workers_id.Any(c => c == tm.ModelID));
var permissions = dbctx.UserPermissions
.Where(p => rusers
.Any(ap => ap.UserID == p.UserID)
&& p.DateStart != null
&& p.DateEnd != null
&& p.DateStart <= sqlDate.Value
&& p.DateEnd >= sqlDate.Value);
if (permissions.Count() < 1)
{
permissions = dbctx.UserPermissions
.Where(p => rusers
.Any(ap => ap.UserID == p.UserID)
&& p.DateStart == null
&& p.DateEnd == null);
var used = dbctx.UserPermissions
.Where(p => rusers
.Any(ap => ap.UserID == p.UserID)
&& p.DateStart != null
&& p.DateEnd != null);
if (permissions.Count() > 0 && used.Count() < 1)
{
var p = permissions.First();
using (Models.TTTDbContext tdbctx = new Models.TTTDbContext())
{
var tp = tdbctx.UserPermissions.SingleOrDefault(tup => tup.UserID == p.UserID);
tp.DateStart = DateTime.Now.Date;
tp.DateEnd = DateTime.Now.Date.AddDays(60);
tdbctx.SaveChanges();
}
此处First()
方法抛出异常:
序列不包含元素
那怎么可能?
编辑: 我不认为用户打开两个浏览器并同时在这里导航,但可能是并发问题?
答案 0 :(得分:1)
您声称只在服务器日志中找到了这个,并且在调试期间没有遇到它。这意味着在这些行之间:
if (permissions.Count() > 0)
{
var p = permissions.First();
其他一些进程或线程更改了您的数据库,因此查询不再匹配任何文档。
这是由permissions
持有一个延迟评估的资源引起的,这意味着查询只在您迭代它时执行(Count()
和First()
)。
所以在Count()
中,执行查询:
SELECT COUNT(*) ... WHERE ...
在那一刻返回一行。然后在外部修改数据,从而导致下一个查询(First()
):
SELECT n1, n2, ... WHERE ...
返回零行,导致First()
抛出。
现在,如何解决这个问题,取决于您,并完全取决于您希望如何为此方案建模。这意味着第二个查询实际上是正确的:在那个时刻,没有更多行符合查询条件。您可以实现一次查询:
permissions = query.Where(...).ToList()
但这意味着你的逻辑操作陈旧的数据。如果您使用FirstOrDefault()
:
var permissionToApply = permissions.FirstOrDefault();
if (permissionToApply != null)
{
// rest of your logic
}
所以这基本上是一个双输的场景。你总是有可能在过时的数据上运行,这意味着下一个代码:
tdbctx.UserPermissions.SingleOrDefault(tup => tup.UserID == p.UserID);
也会抛出。因此,每次查询数据库时,都必须编写代码,使其能够处理不再存在的记录。