![](/img/trans.png)
[英]EF Core 2 throws exception on SaveChanges, after first update for related entities
[英]EF Count() > 0 but First() throws exception
我遇到了一個奇怪的問題。 當用戶訪問我的Web應用程序的任何頁面時,我都會檢查用戶是否有權訪問它,並提供首次試用期。
這是我的代碼:
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()
方法拋出異常:
序列不包含任何元素
那怎么可能呢?
編輯:我不認為用戶打開兩個瀏覽器並同時在此處導航,但是可能是並發問題嗎?
您聲稱您僅在服務器日志中找到了它,而在調試過程中沒有遇到它。 這意味着在這些行之間:
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);
也會扔。 因此,每次查詢數據庫時,都必須以一種可以處理不再存在的記錄的方式編寫代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.