我的数据库中有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。 =)
答案 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
容器是每次删除某些内容时都会更新,它会在删除所有子项之前退出循环。