删除托管子列表的最佳方法。一对多/亲子关系

时间:2016-06-14 18:33:38

标签: c# xamarin realm

我的数据库中有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
}

每次加载我的应用程序时,网页命中都会获取产品列表,然后开始在Realm数据库中管理它们,它会在TableView中显示产品。单击表视图中的某个产品时,将获得“报告”列表。报告列表由使用产品ID的其他网络点击获取。每次从Web获取新的报告列表时,我都需要从Realm数据库中删除链接到一个特定产品的所有旧Report对象(按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

最后,这是我用来将我的子对象(来自网络的报告)添加到父(产品)的方法。

// 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。 =)

1 个答案:

答案 0 :(得分:4)

官方领域的回答 - 你对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容器是每次删除某些内容时都会更新,它会在删除所有子项之前退出循环。