C# 删除托管子列表的最佳方法。一对多/亲子关系
我的数据库中有两个托管对象,如下所示C# 删除托管子列表的最佳方法。一对多/亲子关系,c#,xamarin,realm,C#,Xamarin,Realm,我的数据库中有两个托管对象,如下所示 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 } 每次加载我的应用程序时,web
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
}
每次加载我的应用程序时,web hit都会获取一个产品列表,然后开始在领域数据库中管理它们,它会在TableView中显示这些产品。单击表视图中的一个产品时,将获得一个报告列表。报告列表由另一个使用产品id的web访问获取。每次我从web获取新的报告列表时,我都需要从域数据库中删除链接到一个特定产品(按id)的所有旧报告对象
这就是困惑所在。根据这一点,目前不支持级联删除。我假设这意味着删除了像上面那样的关系中的对象。因此,目前移除子对象(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)
//id作为参数由函数传入
var reportsById=realm.All.Where(r=>r.Product.Id==Id.ToList();
foreach(reportsById中的var报告)
{
//删除具有事务的对象
使用(var trans=realm.BeginWrite())
{
域。删除(报告);
trans.Commit();
}
}
//然后简单地将新报告添加到我的旧产品中
//伪码
var newreports=getnewreports()
新报表中的foreach报表
product.Reports.add(报告)
方法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
//获取当前产品对象
var currentProduct=realm.All.Where(p=>p.Id==Id.ToList().FirstOrDefault();
foreach(currentProduct.Reports中的var报告)
{
//删除具有事务的对象
使用(var trans=realm.BeginWrite())
{
域。删除(报告);
trans.Commit();
}
}
//再次向产品添加新报告
最后,这是我用来将我的子对象(来自web的报告)添加到父对象(产品)的方法
//首先
var webReports=等待FetchWebReport();//IList类型
/...../
//然后
var currentProduct=Realm.blah()…//使用查询从领域数据库获取
foreach(webReports中的var报告)
{
//使用事务管理对象
使用(var trans=realm.BeginWrite())
{
//添加对父产品的引用
report.Parent=currentProduct;
//添加到产品中的子列表
currentProduct.Reports.Add(报告);
trans.Commit();
}
}
有人有什么想法/意见吗?请随意挑选我当前的代码。指出问题。感谢您的开发者。=) 官方领域答案-你的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
}
}
});
对样本的重要修复-使用ToList
realm.Write(() => {
foreach (var r in delP.Reports.ToList())
realm.Remove(r);
realm.Remove(delP); // lastly remove the parent
});
您在B中的方法几乎是正确的,但它忽略了一个事实,即
foreach(currentProduct.Reports中的var报告)
正在迭代一个实时列表。因为报告
容器在您每次删除某个内容时都会更新,它将在删除所有子项之前退出循环。不客气。通常我们都在忙着告诉人们他们不必使用ToList
。这是一个罕见的例外;-)哈哈,很有趣,你不认为你可以告诉我这件事,或者把我链接到一个帖子上吗?我一直使用ToList。在大多数.NET代码中使用ToList没有什么错。但是,它确实会在内存中生成一个容器。RealmResults类是一个活动容器,当您更改其他线程中的对象时,它会更新。它也是惰性的,并且只在枚举结果时创建对象。如果您只有几十个对象,那么懒惰方面并不重要,但是如果您有数千个对象的结果,并且称为ToList,那么可能会在时间和堆活动方面产生显著的影响。
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
}
}
});
var delId = 1;
var delP = realm.All<Product>().First(p => p.Id == delId);
if (delP == null)
return;
realm.Write(() => {
foreach (var r in delP.Reports.ToList())
realm.Remove(r);
realm.Remove(delP); // lastly remove the parent
});