我很擅长保存到coreData并使用iOS dev。
我想要实现的目标:
我希望能够在我的数据库中拥有一个具有唯一标识符/用idFB
拉取的用户,并且该用户可以创建和检索他们的工作例程。
我走了多远?
我设法(我认为)创建了一个方法,可以从与routineName
关联的Routine entity
中正确检索User
。请参阅fetch
方法。
我的问题:
我认为我没有使用正确的实体关系关联User (usersExercise) <--->> Routine (userID)
进行保存。换句话说,我认为我的save
方法不正确...因为我将整个用户保存到userID并且它感觉不对?主要是因为当它吐出Routine.userID
时它会拉动整个关联用户而不是特定ID?我真的不知道会发生什么
有人可以帮我正确地构建这些方法吗?我对coreData保存和建立正确关系的整个过程非常困惑。
- (void) save {
Routine *newRoutine = [NSEntityDescription insertNewObjectForEntityForName:@"Routine" inManagedObjectContext:context];
newRoutine.users = [self getCurrentUser];
newRoutine.routineName = @"myRoutine Test Name";
NSError* error;
[context save:&error ];
NSLog(@"Saved now try to fetch");
[self fetch];
}
-(void) fetch {
NSFetchRequest *fetchRequestItems = [[NSFetchRequest alloc] init];
NSEntityDescription *entityItem = [NSEntityDescription entityForName:@"Routine" inManagedObjectContext:context];
[fetchRequestItems setEntity:entityItem];
User* user = [self getCurrentUser];
// if i try [[self getCurrentUser] usersRoutine] it shows an error
[fetchRequestItems setPredicate:[NSPredicate predicateWithFormat:@"users == %@",user]];
//Sort by last edit ordered
NSArray *sortDescriptors = [NSArray arrayWithObjects:nil];
[fetchRequestItems setSortDescriptors:sortDescriptors];
NSError *error = nil;
NSArray* Routines = [context executeFetchRequest:fetchRequestItems error:&error];
NSLog(@"result %@", [(Routine *)Routines[0] users] );
}
-(User *)getCurrentUser {
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:@"User" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
if (_appDelegate.isFB)
{
request.predicate = [NSPredicate predicateWithFormat:@"idFB LIKE %@",_appDelegate.fdID];
NSError *error = nil;
NSArray *matches = [[context executeFetchRequest:request error:&error] mutableCopy];
return (User *)matches[0];
} else
{
NSLog(@"CreateRoutinePOPUP NON FB TO BE TESTED");
request.predicate = [NSPredicate predicateWithFormat:@"email LIKE %@",_appDelegate.currentUser];
NSError *error = nil;
NSArray *matches = [[context executeFetchRequest:request error:&error] mutableCopy];
return (User *)matches[0];
}
这是获取中的NSLog正在打印的内容:
2013-04-28 22:33:26.555 iGym[7916:c07] result <User: 0xa480580> (entity: User; id: 0xa495a00 <x-coredata://D87CEBB4-016C-4A1B-802C-2D1117BB3E51/User/p1> ; data: {
dob = "1986-12-26 00:00:00 +0000";
email = ".com";
firstTime = nil;
gender = male;
height = nil;
idFB =3333;
idUserExternal = 0;
idUserInternal = 0;
isPT = nil;
language = "en_US";
location = "London, United Kingdom";
metricSystem = nil;
name = Joan;
nickname = nil;
password = nil;
surname = Thurft;
usersExercise = "<relationship fault: 0xa4824a0 'usersExercise'>";
usersRoutine = (
"0xa495f00 <x-coredata://D87CEBB4-016C-4A1B-802C-2D1117BB3E51/Routine/p6>",
"0xa4877e0 <x-coredata://D87CEBB4-016C-4A1B-802C-2D1117BB3E51/Routine/p1>",
"0xa4877f0 <x-coredata://D87CEBB4-016C-4A1B-802C-2D1117BB3E51/Routine/p2>",
"0xa487800 <x-coredata://D87CEBB4-016C-4A1B-802C-2D1117BB3E51/Routine/p3>",
"0xa487810 <x-coredata://D87CEBB4-016C-4A1B-802C-2D1117BB3E51/Routine/p4>",
"0xa487820 <x-coredata://D87CEBB4-016C-4A1B-802C-2D1117BB3E51/Routine/p5>"
);
weight = nil;
})
当我添加NSLog时(@“获取当前结果%@”,[(User *)匹配[0] usersRoutine]);到getCurrentUser方法,我得到整个用户的数据和关系说
usersExercise = "<relationship fault: 0xa464730 'usersExercise'>";
答案 0 :(得分:7)
核心数据与使用标准数据库不完全一样,您可以将一些外键(如userID
)分配给另一个表,在该表中需要与User
对象建立关系,然后使用该外来ID查找像exercise.where('user_id = ?', userID)
这样的关系。相反,您可以定义实际关系,并让Core Data处理幕后的所有内容,以设置任何连接表或外键。
您可以在User
实体中拥有exercises
和routines
两个映射到Exercise
的关系,而不是如何设置它Routine
个实体,如果它是一个拥有且属于多对的关系,那么Exercise
和Routine
上的users
就会产生反比关系。现在,您需要将usersExercise
替换为exercises
,usersRoutine
替换为routines
,然后userID
替换为users
Exercise
和Routine
个实体。
即使你实际上并不需要这种反向关系,你仍然需要它,因为Core Data将它用于数据完整性目的,如果你让它无人居住,Xcode会给你一个警告。
当您设置这些关系时,您将调用user.exercises
之类的例程或练习,它将返回该用户的相关练习集。正如您所注意到的,Core Data将返回他们称之为fault
的关系,因为这种关系会被触发,并且当您确实需要该关系的内容时会返回数据。存在故障,因此您只需返回所需的信息,而不是在数据集上运行不必要的查询。
另外需要注意的是,Core Data并不像您一样引用userID
之类的唯一ID。相反,Core Data中的每个对象都有[objectName objectID]
找到的唯一ID(只有在保存到数据存储后才是永久ID)。除了特殊情况之外,您真的不需要在实体上设置唯一ID作为属性。
此外,你真的不需要使用那些独特的objectID
,除非你像在多线程应用程序中一样传递对象以进行后台处理,在这种情况下NSManagedObjectID
是线程 - 安全,您可以使用它在后台线程/托管对象上下文中再次查找对象。
我真的建议您阅读核心数据的简介,例如http://www.raywenderlich.com/934/core-data-on-ios-5-tutorial-getting-started
如果您习惯于正常的数据库设置/架构,首次转换为Core Data可能会有点奇怪,但是一旦您习惯了它,它实际上要快得多,并处理幕后的所有艰苦工作为了你。
从评论中更新:
你误解了核心数据中的关系概念。在Core Data中,关系不会像典型的数据库连接关系那样返回关联的ID。相反,它会返回一个错误,当您需要来自该关系的数据时会触发该错误。因此,它不会返回整个User
对象,而是返回fault
对象User
对象,当您执行exercise.user.name
你的代码的工作方式与保存时的代码完全一样,你的错误假设不是这样。
答案 1 :(得分:0)
您需要使用提供的方法在一对多对象中添加“多个对象”。在您的情况下,它被称为addRoutineObject:
尝试这种新的保存方法:
- (void) save {
Routine *newRoutine = [NSEntityDescription insertNewObjectForEntityForName:@"Routine" inManagedObjectContext:context];
newRoutine.routineName = @"myRoutine Test Name";
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:@"User" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
NSArray *matches;
NSError *error = nil;
if (_appDelegate.isFB)
{
request.predicate = [NSPredicate predicateWithFormat:@"idFB LIKE %@",_appDelegate.fdID];
matches = [[context executeFetchRequest:request error:&error] mutableCopy];
} else
{
NSLog(@"CreateRoutinePOPUP NON FB TO BE TESTED");
request.predicate = [NSPredicate predicateWithFormat:@"email LIKE %@",_appDelegate.currentUser];
matches = [[context executeFetchRequest:request error:&error] mutableCopy];
}
if (matches.count == 0)
{
NSLog(@"no user matched");
}
else
{
User *aUser = [matches objectAtIndex:0];
[aUser addRoutineObject:newRoutine];
if (![context save:&error])
{
NSLog(@"couldn't save: %@", [error localizedDescription]);
}
}
}