【问题标题】:Best method to remove managed child lists. One-to-many / parent-child relationships删除托管子列表的最佳方法。一对多/父子关系
【发布时间】:2016-06-14 18:33:37
【问题描述】:

我的数据库中有 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 开发人员。 =)

【问题讨论】:

    标签: c# xamarin realm


    【解决方案1】:

    官方领域的答案 - 你几乎是正确的 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 容器删除一些东西,它会在删除所有孩子之前退出循环。

    【讨论】:

    • 不客气。通常我们会忙着告诉人们他们不必必须使用ToList。这是一个罕见的例外 ;-)
    • 哈哈有趣不要以为你可以告诉我或者链接我到一个帖子吗?我一直使用 ToList。
    • 在大多数 .NET 代码中使用 ToList 没有任何问题。但是,它确实会在内存中生成一个容器。 RealmResults 类是一个实时容器,当您在其他线程中更改对象时会更新它。它也是 lazy 并且仅在您枚举结果时创建对象。如果您只有几十个对象,惰性方面并不重要,但如果您有数千个对象的结果并调用 ToList,则时间和堆活动可能会受到显着影响。 realm.io/docs/xamarin/0.76.0/api/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多