2016-06-14 65 views
2

我在我的數據庫中有2個管理對象,看起來像這樣。刪除管理的子列表的最佳方法。一對多/親子關係

public class Product : RealmObject 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public string Date { get; set; } 
    public RealmList<Report> Reports { get; } // child objects 
} 

public class Report : RealmObject 
{ 
    public int Id { get; set; } 
    public string Ref { get; set; } 
    public string Date { get; set; } 
    public Product Parent { get; set; } // Parent object reference 
} 

每個我的應用程序加載網頁命中一次獲取產品的列表,然後開始在境界數據庫管理他們,這顯示產品中的TableView中。當您單擊表格視圖中的某個產品時,您會看到一份報告列表。報告列表由使用產品ID的另一個Web命中獲取。每當我從網絡獲得新的報告列表時,我都需要從Realm數據庫中刪除所有鏈接到特定產品的舊報告對象(按ID)。

這裏就是混亂。據此https://realm.io/docs/xamarin/latest/#current-limitations目前不支持級聯刪除。我認爲這意味着刪除了像上面這樣的關係中的對象。所以暫時去除子對象(RealmList)的最佳方法是什麼?到目前爲止,我已經提出了兩種方法。這裏有一些代碼。

解決方法A

// id is passed in as a param by function 
var reportsById = realm.All<Report>.Where(r => r.Product.Id == id).ToList(); 

foreach (var report in reportsById) 
{ 
    // Delete an object with a transaction 
    using (var trans = realm.BeginWrite()) 
    { 
     realm.Remove(report); 
     trans.Commit(); 
    } 
} 

// Then simply add the new reports to my old Product 
// Pseudo code 
var newreports = getnewreports() 
foreach report in newreports 
    product.Reports.add(report) 

方法B:

// Get the current Product object 
var currentProduct = realm.All<Product>.Where(p => p.Id == id).ToList().FirstOrDefault(); 

foreach (var report in currentProduct.Reports) 
{ 
    // Delete an object with a transaction 
    using (var trans = realm.BeginWrite()) 
    { 
     realm.Remove(report); 
     trans.Commit(); 
    } 
} 

// Add new reports to product again 

最後,這是我用我的子對象(從Web報表)添加到父的辦法(產品)。

// First 
var webReports = await FetchWebReport(); // IList<Report> type 

/...../ 

// Then 
var currentProduct = Realm.blah()... // get from realm database with query 

foreach (var report in webReports) 
{ 
    // Manage object with a transaction 
    using (var trans = realm.BeginWrite()) 
    { 
     // Add reference to parent product 
     report.Parent = currentProduct; 

     // Add to child list in product 
     currentProduct.Reports.Add(report); 

     trans.Commit(); 
    } 
} 

有沒有人有任何想法/輸入?隨意挑選我目前的代碼。指出問題。感謝Realm Devs。 =)

回答

3

官方境界的答案 - 你幾乎權利同B ;-)

注意下面的示例使用Write(lambda)風格,而不是明確的事務的創建和提交。它更簡潔一些,但做同樣的工作。

我也循環裏面的而不是做很多交易。速度更快,意味着相關更新的收集只在單個事務中進行。

創建一些樣本層次

realm.Write (() => { 
    for (var pid = 1; pid <= 4; ++pid) { 
     var p = realm.CreateObject<Product>(); 
     p.Id = pid; 
     p.Name = $"Product {pid}"; 
     for (var rid = 1; rid <= 5; ++rid) { 
      var r = realm.CreateObject<Report>(); 
      r.Id = rid+pid*1000; 
      r.Ref = $"Report {pid}:{rid}"; 
      p.Reports.Add(r); // child object added to relationship 
     } 
    } 
}); 

執行刪除

找到我們想要做一個僞級聯刪除的對象 - 我直接使用LINQ First得到物體。

var delId = 1; 
var delP = realm.All<Product>().First(p => p.Id == delId); 
if (delP == null) 
    return; 

重要的修補來樣 - 使用ToList

realm.Write(() => { 
    foreach (var r in delP.Reports.ToList()) 
     realm.Remove(r); 
    realm.Remove(delP); // lastly remove the parent 
}); 

你B中的做法是接近正確它忽略了一個事實foreach (var report in currentProduct.Reports)是一個迭代現場名單。因爲每次刪除東西時都會更新Reports容器,所以在移除所有子項之前,容器會退出循環。

+0

謝謝!這太棒了 –

+0

不客氣。通常我們都忙着告訴人們他們不*必須使用'ToList'。這是一個罕見的例外;-) –

+0

哈哈有趣的不假設你可以告訴我關於這一點,或者鏈接到我的帖子?我一直使用ToList。 –