2016-06-14 3 views
2

私のデータベースには、このような2つの管理オブジェクトがあります。管理された子リストを削除する最適な方法。 1対多/親子関係

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 
} 

私のアプリは、Webヒットをロードするたびに、それはテーブルビューで商品を表示し、レルムのデータベースにそれらを管理開始し、その後製品のリストを取得します。テーブルビューで製品の1つをクリックすると、レポートのリストが表示されます。レポートのリストは、製品IDを使用して別のWebヒットによって取得されます。 Webから新しいレポートのリストを取得するたびに、特定の製品(ID別)にリンクされているすべての古いレポートオブジェクトをレルムデータベースから削除する必要があります。

ここに混乱があります。これによれば、カスケード削除は現在サポートされていません。私は、上記のような関係で削除されたオブジェクトを意味すると仮定します。だから当分の間、物事を壊すことなく、子オブジェクト(RealmList)を取り除く最善の方法です。私はこれまでに2つのアプローチを思いついた。ここにいくつかのコードがあります。

アプローチ

// 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 

そして最後に、これは私が親に私の子オブジェクト(ウェブからの報告)を追加するために使用される手法であります(製品)。

// 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; 

重要な修正 - BでToList

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

あなたのアプローチを使用することがforeach (var report in currentProduct.Reports)ライブリストを反復しているという事実を無視しほぼ正しかったけど。Reportsコンテナは、何かを削除するたびに更新されるため、すべての子を削除する前にループを終了します。

+0

ありがとうございました!それは素晴らしいです –

+0

あなたは大歓迎です。通常、ToListを使わない*人たちに話をしています。これはまれな例外です;-) –

+0

興味深いことに、あなたは私にそのことを教えてもらえませんか?私は常にToListを使用します。 –

関連する問題