【问题标题】:Struggling with CoreData relationships and deleting objects挣扎于 CoreData 关系和删除对象
【发布时间】:2014-05-29 16:58:19
【问题描述】:

我对 Objective-C 比较陌生,并试图通过学习 CoreData 来学习,尽管有大量的 Google 搜索。我对 mySQL 和关系表有很好的了解,但我似乎无法思考如何让实体在 CoreData 中相互关联。

我喜欢在学习 CoreData 之类的东西时为自己创建一些小项目,所以我总结了汽车服务跟踪器的简单概念(如换油、制动工作等)。

我有 2 个实体代表车辆和换油,就像这样......

和

...以及它们各自的关系。我不确定这是否需要一对一或一对多的关系,因为车辆会更换很多机油,但也会有很多车辆......所以我猜这是第一件事我需要一些帮助来理解。

我正在使用 SQLLite Manager 来观察数据模型的情况。当我将车辆添加到我的车辆实体(基本上保存 UITextFields)时,我可以看到对象位于正确的实体中......

...当我将换油添加到特定车辆时,我可以看到这些对象也被放入了它们的正确实体中...

.. 但正如您从以下内容中看到的那样,在尝试将特定换油与特定车辆关联时似乎存在断开...

现在,对于重要的问题......

1)。我如何让单独的机油更换仅与他们各自的车辆相关?现在,无论选择哪种车辆,都会显示所有换油。我确信这与更新我获取的结果查询有关,但是正如您从显示的表格中看到的那样,我没有得到相应车辆的相应换油。

2)。这可以通过理解问题 1 来解决……但是如果我删除了特定的车辆,那么我显然还需要删除与该车辆相关的任何换油。

我的保存方法如下。

- (IBAction)save:(id)sender {
Oil *oil = [NSEntityDescription insertNewObjectForEntityForName:@"Oil" inManagedObjectContext:self.managedObjectContext];
Vehicle *vehicle = [NSEntityDescription insertNewObjectForEntityForName:@"Vehicle" inManagedObjectContext:self.managedObjectContext];

// Which Vehicle
// newOil.vehicle = whichVehicle.text;
oil.vehicle = vehicle; // not working

// Format: Mileage
NSNumberFormatter *numberFormat = [[NSNumberFormatter alloc] init];
[numberFormat setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber *myNumber = [numberFormat numberFromString:oilMileage.text];
oil.oilMileage = myNumber;

// Format: Date
NSDateFormatter *dateFormat = [[NSDateFormatter alloc]init];
[dateFormat setDateFormat:@"MM-dd-yyyy"];
oil.oilDate = [dateFormat dateFromString:oilDate.text];

// Format: Notes
oil.oilNotes = oilNotes.text;

// save context
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate saveContext]; }

->

->

->

->

好的,我正在尝试整合 Dan Shelly 的建议(这完全有道理),但是我遇到了一个需要更多指导的障碍。

我的 mainVC 没有使用 tableView 来显示我的车辆(我已将车辆总数限制为 4,我用图标表示它们并将它们绑定回 CoreData 中的车辆 ID)......无论如何,因为它不是一个 tableView 我不能使用以下内容:

Vehicle *existingVehicle = (Vehicle *)[self.fetchedResultsController objectAtIndexPath:indexPath];

...因此,我无法为获取的 Vehicle 对象创建一个实例,然后我可以将其传递给 OilViewController。我有一个 fetchRequest 从 CoreData 返回正确的车辆 ID,但我需要知道如何实际创建对象,以便可以将其传递给 OilViewController。我的 fetchRequest 看起来像这样...

- (void)fetchObjects {
NSLog(@"DVC-fetching Objects\n\n");

// Create Fetch Request
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Vehicle" inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:entity];

// Set Search Criteria
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"vehicleID == %@", vehicleID];
[fetchRequest setPredicate:predicate];

NSError *error;
NSArray *array = [managedObjectContext executeFetchRequest:fetchRequest error:&error];

NSLog(@"Object ID: %@", [array valueForKey:@"objectID"]);
NSManagedObjectID *moID = [array valueForKey:@"objectID"];

if (array != nil) {
    NSUInteger count = [array count]; // May be 0 if the object has been deleted.
    Vehicle *existingVehicle = (Vehicle *)[self.managedObjectContext existingObjectWithID:moID error:&error];
    NSLog(@"Count: %lu", (unsigned long)count);
    NSLog(@"Fetched Vehicle ID: %@",predicate);
    NSLog(@"existingVehicle: %@", existingVehicle);

} else {
    // Deal with error.
}

}

但我收到以下错误:

由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“-[__NSArrayI isTemporaryID]:无法识别的选择器已发送到实例 0x11d5b660”

  • moID 正确返回为“0x8bb1980 x-coredata://6681B331-29F0-448B-82F1-4660E033A460/Vehicle/p1”
  • 数组计数返回“1”[正确]
  • FetchVehicle ID 返回“vehicleID == 1”[也正确]

如何为这个返回的对象创建一个 Vehicle 实例,以便我可以传递它??

【问题讨论】:

  • 无法发布图片。
  • 我为你添加了它们。
  • 感谢 MartinW!我很感激协助......被血腥的声誉警察所阻碍:)

标签: xcode core-data entity-relationship cascade nsfetchrequest


【解决方案1】:

1) 如何让个别换油只与各自的车辆相关?

您已经这样做了……只是您当前将换油与空的Vehicle 对象相关联。这在您的车辆表中也可见 (Z_PK = [3,4,5])。

当您需要添加新的换油时,您可能已经可以访问此换油所针对的相关 Vehicle 对象。
这个Vehicle 对象可能是您在车辆视图控制器中选择的对象。

因此,不必在每次创建换油时都插入 Vehicle 对象,而只需将关系设置为现有车辆(您正在构建对象图,考虑现有对象并将它们相互连接)。

2) 删除:

从图片看来,您设置了删除规则应该是为了实现您的目标。当您删除Vehicle 对象时,级联规则将连同它一起删除相关的换油对象。当您删除换油对象时,相关的Vehicle机油关系将被取消。

总结一下:

获取现有的Vehicle 对象:

//in your vehicle view controller :
Vehicle* existingVehicle = (Vehicle*)[self.fetchedResultsController objectAtIndexPath:indexPath];

将此对象传递给您的“换油视图控制器”。 添加新换油时,将车辆设置为现有对象:

Oil *oil = [NSEntityDescription insertNewObjectForEntityForName:@"Oil" inManagedObjectContext:self.managedObjectContext];
oil.vehicle = existingVehicle; // the one you passed along to this scope
//The rest of the oil content setting
//DON'T FORGET TO SAVE!

您可能希望将您的关系类型更改为一对多类型的关系船(Vehicle 可能有很多换油)。
这不会更改您的换油创建代码。

要查看特定 Vehicle 对象的换油情况,您必须使用传递给换油视图控制器的现有车辆对象,并将其用于 FRC 获取请求的谓词中:

NSPredicate* p = [NSPredicate predicateWithFormat:@"vehicle = %@",existingVehicle];
fetchRequest.predicate = p;

【讨论】:

  • 谢谢 Dan,非常感谢您的帮助。仍然试图围绕所有这些。后续问题;我的 VC 没有使用 tableview 来显示车辆(虽然换油 VC 是 - 但主 VC 更多的是自定义图标布局)。我有一个 fetchrequest 返回所选车辆的正确车辆 ID 值并将其传递给 oilChange VC,但是当我不使用表的“objectAtIndexPath”时如何创建对象“Vehicle *existingVehicle”?
  • 我试过以下code Vehicle *existingVehicle = [[Vehicle alloc] initWithEntity:[array objectAtIndex:0] insertIntoManagedObjectContext:[self managedObjectContext]]; code 但它会引发以下错误:未捕获的异常 'NSInvalidArgumentException',原因:'-[Vehicle managedObjectModel]: unrecognized selector sent to instance 0x1272c5a0'
  • 您不应该“分配初始化”一个托管对象。看看我是如何插入一个新的Oil 对象的。 insertInto... 方法将添加一辆新车,而您想获得一辆现有的(简单的objectAtIndexPath 就可以了)。
  • 丹,我跟着你。谢谢。但是,当我不使用 tableview 时,我仍在努力获取现有的 Vehicle 对象。我尝试使用 fetchRequest 并尝试获取对象引用,但我的语法一定不正确。
  • 在您共享的代码中,您的moID 变量实际上设置为一个数组(在数组上发送valueForKey:... 将返回一个数组)。通过:Vehicle* existingItem = (Vehicle*)[array objectAtIndex:0]; 获取现有项目。显然检查错误,如果你有数组中的任何对象 firs ...
猜你喜欢
  • 2012-01-06
  • 2023-04-06
  • 2014-08-30
  • 1970-01-01
  • 2012-05-31
  • 2013-02-28
  • 1970-01-01
  • 2017-08-20
  • 2021-04-03
相关资源
最近更新 更多