簡體   English   中英

我怎么知道為什么/如何一些LINQ查詢相互協作而另一些不相同?

[英]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個實體,請使用SingleSingleOrDefault 您的應用程序應優雅公正地處理異常。 如果有人發送了無效的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM