MagicalRecord findByAttribute返回反向关系文档的问题

时间:2015-06-27 20:29:15

标签: ios cocoa core-data magicalrecord

我在解决如何使用Core Data和MagicalRecord建模/获取项目时遇到了问题。我有两个实体, User Message ,它们彼此之间存在反向关系:

用户实体

Relationship    Destination    Inverse    Type
-------------------------------------------------
messages        Message        user       To Many

讯息实体

Relationship    Destination    Inverse    Type
-------------------------------------------------
user            User           messages   To One

问题

当给定用户提取消息时,MagicalRecord返回2倍的记录数,因为它匹配useruser.messages.user keyPaths的属性:

- (NSArray *)fetchMessagesByUser:(NSString *)identifier {

    // returning 2x the records it should
    return [Message MR_findByAttribute:@"user.identifier" withValue:identifier];
}

我应该改变我使用MagicalRecord的方式,还是我的核心数据模型存在根本问题?

1 个答案:

答案 0 :(得分:0)

当我使用to many关系使用MagicalRecord设置应用程序,然后运行应用程序几次时,用户会一次又一次地保存,因此我看到消息数量的双倍(和三倍),因为相同的用户已多次保存。

如果您尝试在代码中更改用户的属性值 - 以便下次运行程序时创建具有唯一属性的用户 - 我想您会看到消息的数量将会是你所期待的。

您可以通过添加此代码来查看所有用户:

NSArray* users = [User MR_findAll];

for(User* user in users) {
    NSLog(@"%@", [user name]);  //Log whatever attributes you want
}

如果我说得对,那就会发现你有多个具有相同属性的用户。

======

因为关于MagicalRecord的信息很少,我会发布我为设置应用程序所做的事情。我使用Xcode 6.3.2。

1)我创建了一个名为MagicalRecord2的OSX Cocoa应用程序。我做了NOT检查使用核心数据。

2)在终端窗口中,我执行了命令:

~$ gem install cocoapods  //However, you probably need to use sudo(see below)

在我的系统上,我安装了多个版本的ruby(使用rvm来管理它们),你永远不应该使用sudo和rvm,但是如果你只有系统安装ruby,那么你需要使用sudo安装gem:$ sudo gem install cocoapods

3)在终端中,我将目录(cd)更改为我的项目目录:

~$ cd ~/xcode_projects/MagicalRecord2/

4)在项目目录中,我用这个创建了一个名为Podfile的文件 含量:

pod "MagicalRecord"

然后我保存了文件。

5)然后我运行了命令

~/xcode_projects/MagicalRecord2$ pod update

当该命令结束时,它打印出消息:

  

[!]请关闭所有当前的Xcode会话并使用   从现在开始,MagicalRecord2.xcworkspace用于此项目。

所以我退出Xcode,我使用Finder导航到我的项目目录,然后点击MagicalRecord2.xcworkspace打开Xcode。如果在Project Navigator中展开一些组,您很快就会看到正常的AppDelegate.h / .m文件等。

6)在AppDelegate中(或者你可以创建一个你创建的NSWindowController子类),我添加了以下导入:

#import <MagicalRecord/MagicalRecord.h>

7)然后我创建了模型:File>New>OSX:CoreData>Data Model

我将文件命名为MyModels.xcdatamodeld并接受了默认值。然后在Project Navigator中,我单击了MyModels.xcdatamodeld文件,该文件打开了实体编辑器。在实体编辑器的底部,我点击了添加实体。然后我双击“实体”并更改了#34;实体&#34;到“用户”。在Attributes下,我单击+,然后添加了String类型的name属性。以类似的方式,我添加了一个Message实体,其“text”属性类型为String。

enter image description here

然后我再次点击User实体,在Relationships部分点击+,然后在我输入的关系列下messages(小写,复数),目的地我选择了Message。接下来,在Xcode窗口的最右侧,顶部有一组三个图标,我选择了第三个图标 - Data Model Inspector。在突出显示messages关系的情况下,如果查看数据模型检查器,您会看到一个标题为 Relationship ,在该部分中,您可以看到Type的值为{ {1}}。将To One更改为Type

enter image description here

接下来,在实体编辑器的左侧,单击To Many实体,然后在 Relationships 部分中单击“+”,并将关系命名为“user” '(单数,小写),反向选择Message

enter image description here

如果您返回messages实体,您会在 Relationships&gt; Inverse 下看到它现在显示为User

数据模型检查器中还有其他值得设置的设置,但您必须阅读这些设置。对于此演示,不需要任何其他内容。

8)在Project Navigator中仍然突出显示user,查看屏幕顶部,然后在Xcode菜单栏中选择MyModels.xcdatamodeld。在弹出窗口中,我选中了Editor>Create NSManagedObject Subclass,然后点击了下一步,然后我检查了MyModelsUser,然后又点击了下一步。下一个屏幕真的搞砸了我:Xcode会问你要保存要创建的新文件的位置。默认情况下,Xcode会将文件添加到项目目录之外,但它们会出现在Project Navigator中,因此它们看起来就像是在项目中。但后来,当我尝试导入这些文件时,我收到一条错误消息,说无法找到这些文件。我的回答是,“这是什么〜!@#〜!@#!@你的意思是??!这些文件就在Project Navigator中!“

因此,请务必仔细选择将文件添加到项目内的组(即文件夹),例如MagicalRecord2组(文件夹)对我来说。这有点令人困惑,因为有两个或三个名为“YourProjectName”的东西,当您选择保存新文件的位置时,您必须导航到名为“YourProjectName”的组(文件夹)。不要接受默认位置。

如果您正确执行操作,您将在“YourProjectName”组(文件夹)中看到新文件User.h / .m和Message.h / .m。以下是不正确的情况:

enter image description here

查看顶部的文件如何不在MagicalRecord2组(文件夹)中?

9)现在设置MagicalRecord:

Message

正如您所看到的,您只需要两行来设置Magical Record,而后者将负责为您设置Core Data。

10)接下来,编写一个方便的方法,您可以调用该方法来创建和保存新用户:

//
//  AppDelegate.m
//  MagicalRecord2
//


#import "AppDelegate.h"
#import <MagicalRecord/MagicalRecord.h>

@interface AppDelegate ()

@property (weak) IBOutlet NSWindow *window;
@end

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    // Insert code here to initialize your application

    [MagicalRecord setupCoreDataStackWithStoreNamed:@"MyDatabase.sqlite"];
}

- (void)applicationWillTerminate:(NSNotification *)aNotification {
    // Insert code here to tear down your application

    [MagicalRecord cleanUp];
}

@end

11)使用MagicalRecord查询核心数据:

#import "AppDelegate.h"
#import <MagicalRecord/MagicalRecord.h>
#import "User.h"
#import "Message.h"

@interface AppDelegate ()
...
...

- (void)persistNewUserWithName:(NSString*) name {

    NSManagedObjectContext* defaultContext =
    [NSManagedObjectContext MR_defaultContext]; //[NSManagedObjectContext MR_contextForCurrentThread] => deprecated

    User* myUser = [User MR_createEntityInContext:defaultContext]; //Requires that you import User.h.
    [myUser setName: name];

    Message* msg1 = [Message MR_createEntityInContext:defaultContext];  //Requires that you import Message.h
    [msg1 setText:@"Hello"];
    [msg1 setUser:myUser];

    Message* msg2 = [Message MR_createEntityInContext:defaultContext];
    [msg2 setText:@"Goodbye"];
    [msg2 setUser:myUser];

    //I commented out the following line so that the database starts out  
    //empty every time I run the project:

    //[defaultContext MR_saveToPersistentStoreAndWait];  //[defaultContext MR_save] => deprecated

}

@end

我收到错误消息,说找不到文件@implementation AppDelegate - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // Insert code here to initialize your application [MagicalRecord setupCoreDataStackWithStoreNamed:@"MyDatabase.sqlite"]; [self persistNewUserWithName:@"Rokkor"]; NSArray* users = [User MR_findAll]; NSLog(@"User count: %lu", (unsigned long)[users count]); for(User* user in users) { NSLog(@"%@", [user name]); } NSArray* matchingMessages = [Message MR_findByAttribute:@"user.name" withValue:@"Rokkor"]; //When you search in the Message entity, as above, you can write "user.name", //but if you search in the User entity, you cannot write "messages" for (Message* msg in matchingMessages) { NSLog(@"%@", [msg text]); } } 。在User.m中,有一行:

NSManagedObject.h

我注意到这一行,事情似乎有效。 Xcode创建了该文件,我不确定为什么它为一个不存在的文件创建了一个带有import语句的文件。

这是控制台输出:

#import NSManagedObject.h

以下是其他几个选项:

1)您可以使用块来获取defaultContext并保存数据:

2015-06-28 19:42:24.845 MagicalRecord2[2924:73871] Created new private queue context: <NSManagedObjectContext: 0x6000001e7100>
2015-06-28 19:42:24.845 MagicalRecord2[2924:73871] Set root saving context: <NSManagedObjectContext: 0x6000001e7100>
2015-06-28 19:42:24.845 MagicalRecord2[2924:73871] Created new main queue context: <NSManagedObjectContext: 0x6080001e4900>
2015-06-28 19:42:24.846 MagicalRecord2[2924:73871] Set default context: <NSManagedObjectContext: 0x6080001e4900>
2015-06-28 19:42:24.847 MagicalRecord2[2924:73871] User count: 1
2015-06-28 19:42:24.847 MagicalRecord2[2924:73871] Rokkor
2015-06-28 19:42:24.848 MagicalRecord2[2924:73871] Hello
2015-06-28 19:42:24.848 MagicalRecord2[2924:73871] Goodbye

据推测,saveWithBlock()定义如下:

 [MagicalRecord saveWithBlock:^(NSManagedObjectContext* defaultContext) {

     User* myUser = [User MR_createEntityInContext:defaultContext];
     [myUser setName: name];


     Message* m1 = [Message MR_createEntityInContext:defaultContext];
     [m1 setText:@"Hello"];
     [m1 setUser:myUser];

     Message* m2 = [Message MR_createEntityInContext:defaultContext];
     [m2 setText:@"Goodbye"];
     [m2 setUser:myUser];

 }];

因此,saveWithBlock()会自动保存您添加到上下文中的任何内容。

2)查询数据时可以使用过滤器:

(void)saveWithBlock:(void(^)(NSManagedObjectContext*))yourBlock {

    NSManagedObjectContext* context =
        [NSManagedObjectContext MR_defaultContext]; 

    yourBlock(context)

    [context MR_saveToPersistentStoreAndWait];
}