[英]How can I tell why/how some LINQ queries work with each other and others don't?
參加以下EF課程:
public class Person
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public IEnumerable<Property> Property { get; set; }
}
public class Property
{
public int ID { get; set; }
public string Name { get; set; }
public bool Lock { get; set; }
public Person Person { get; set; }
public int PersonID
}
我幾乎可以讓一切按預期工作 - 包括刪除所有屬性的Person刪除操作。 但是,隨着我的代碼變得越來越復雜,我想讓邏輯稍微提高一些。
在上面的例子中,我們在其他地方有一些東西會為屬性設置bool鎖。 在這種情況下,我想在該人的任何屬性具有true的鎖定時禁用人員刪除。
默認的刪除控制器代碼具有:
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
var person = await _context.People
.FirstOrDefaultAsync(m => m.ID == id);
if (person== null)
{
return NotFound();
}
return View(person);
}
刪除確認有:
public async Task<IActionResult> DeleteConfirmed(int id)
{
var person= await _context.people.FindAsync(id);
_context.people.Remove(person);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
我知道做我想做的代碼是:
foreach (var item in person.Property)
{
if item.locked==true
return("error")
}
現在有趣的明星! - 我以前使用的屬性上的舊EF4虛擬關鍵字不起作用 - 因此,我無法迭代屬性,因為它當前為null。 在大多數情況下,我必須調用.include()
在第一次刪除時,這會修改:
var person = await _context.People
.FirstOrDefaultAsync(m => m.ID == id);
至
var person = await _context.People.Include(x=>x.property)
.FirstOrDefaultAsync(m => m.ID == id);
這似乎工作正常。
但是,第二個:
var person = await _context.people.FindAsync(id);
似乎不起作用。 我把.Include
放進去的那一刻,它說明錯誤CS1061沒有FindAsync的定義。
老實說,我不太清楚首先要看兩種不同的ID方式是什么需要......我只能假設在第一次刪除中尋找可能不存在的ID時,首先是firstordefault
的最好的,當確認刪除時, find
最好....但是,這是腳手架的作用,我覺得我不知道這個問題。
然而,我想成為一個更好的開發人員,並希望了解代碼和未來的問題,我怎么知道什么可以組合,什么不能,因為我不覺得我在這里學習,我只是隨機嘗試不同的東西,直到找到一個有效的組合。
一些事情:我會考慮在啟用“刪除”按鈕之前檢查此人是否已鎖定,或者在單擊“刪除”按鈕時立即檢查是否已鎖定,而不是確認刪除。
使用此代碼:
var person = await _context.People
.FirstOrDefaultAsync(m => m.ID == id);
if (person== null)
return NotFound();
return View(person);
實體應表示數據狀態,而不是視圖狀態。 將實體返回到視圖將導致問題。 如果支持/啟用延遲加載,這可能會在延遲加載由序列化觸發時觸發性能問題,也可能由於循環引用而導致錯誤。 它公開了有關您的數據結構的更多信息,以及客戶端不需要的一般數據(更多數據通過網絡和更多黑客信息)。 相反,利用ViewModel POCO類只包含您的視圖所需的數據並使用.Select()
來填充它。
接下來,避免使用FirstOrDefault
的拐杖。 這可能導致隱藏的意外錯誤。 如果預期有1個實體,請使用Single
或SingleOrDefault
。 您的應用程序應優雅公正地處理異常。 如果有人發送了無效的ID,則失敗並終止會話。 基本上不要相信客戶不要亂動。
var person = await _context.People
.Select(x => new PersonViewModel
{
PersonId = x.ID,
Name = x.FirstName + " " + x.LastName,
// etc.
}).SingleAsync(x => x.ID == id);
return View(person);
在確認時檢查數據狀態,您收到ID並想要在發出刪除之前確認,您可以查詢所需的詳細信息,但是如果您要信任該ID,則不需要整個實體。 不需要這樣的東西:
foreach (var item in person.Property)
{
if item.locked==true
return("error")
}
代替:
var isLocked = context.People.Where(x => x.ID == id)
.Select(x => x.Property.Any(p => p.isLocked))
.Single();
如果找不到人員ID,則拋出此值,如果該人員的任何屬性條目被鎖定,則返回Bool True為假。
從那里你可以使用一個簡單的“技巧”來刪除一個實體,而無需先加載它:
if (!isLocked)
{
var person = new Person { ID = id };
context.People.Attach(person);
context.People.Remove(person);
context.SaveChanges();
}
或者,如果要加載Person以訪問其他屬性,例如創建審計記錄或者可能希望在錯誤消息中始終顯示信息,則可以使用以下示例替換上述示例:
var personData = context.People.Where(x => x.ID == id)
.Select(x => new
{
Person = x,
IsLocked = x.Property.Any(p => p.isLocked))
}).Single();
if (!personData.isLocked)
{
context.People.Remove(personData.Person);
context.SaveChanges();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.