CoreData多对多查找重复项

时间:2015-05-06 06:58:54

标签: ios core-data join nspredicate predicate

我正在使用谓词搜索与任何其他用户具有相同首选项的用户

用户<< - >>首

鉴于以下状态;我想检查一个新的注册用户

(Sam, nickname: "foo", language: "english")

查看是否有任何现有用户具有相同的首选项。可以有任意数量的偏好类型。在这种情况下,它会检测到Sally具有相同的选择

用户

| Name  |
| Sally |
| John  |

PreferenceTypes

| Name         |
|  nickname    |
|  language    |
|   ....       |

使用UserPreferences

User       PreferenceTypes      Selection
Sally  |   nickname         |     "foo"
Sally  |   language         |     "english"
John   |   nickname         |     "bar"
John   |   language         |     "english"

2 个答案:

答案 0 :(得分:1)

这是您设置模型的方法:

User <---->> Preference <<-----> PreferenceType

User.name                  // name string
User.preferences           // to-many to Preference

Preference.value           // the value, or "selection"
Preference.user            // to-one to User
Preference.type            // to-one to PreferenceType

Preference.name            // name of preference, such as "language" 
PreferenceType.preferences // to-many relationship to Preference

您的谓词需要一个子查询,并且在资源使用方面会非常“昂贵”。我假设允许一些用户具有其他用户没有的偏好,即,当我们知道可能的偏好的总数时,我们不知道一个特定用户具有的偏好的数量。我无法从头脑中写出这个问题,我不得不考虑一下。 ---任何人?

一种实用的方法是首先获取用户的子集,例如具有完全相同昵称的用户。使用如下谓词获取首选项对象会更简单:

[NSPredicate predicateWithFormat:
   @"type.name = 'nickname' && value = %@ && not (user = %@)", userNickname, user];

在小的用户子集上(由foundPreference.user引用),您可以运行您编写的自定义方法(hasSamePreferences),您可以在其中迭代首选项并检查是否存在和相等。

-(BOOL)hasSamePreferencesAsUser:(User*)otherUser {
    NSSet *myPreferenceKeys = [self.preferences valueForKeyPath:@"type.name"];
    NSSet *otherPreferenceKeys = [otherUser.preferences valueForKeyPath:@"type.name"];
    if (myPreferenceKeys.count != otherPreferenceKeys.count) {
       return NO;
    }
    for (NSString *key in myPreferenceKeys) {
       if (![otherPreferenceKeys containsObject:key]) {
          return NO;
       }
       NSPredicate *keyFilter = [NSPredicate predicateWithFormat:@"type.name = %@", key];
       // String only for demonstration
       NSString *myValue = [self.preferences 
            filteredArrayUsingPredicate:keyFilter].firstObject;
       NSString *otherValue = [otherUser.preferences 
            filteredArrayUsingPredicate:keyFilter].firstObject;
       if (![myValue isEqualToString:otherValue]) {
          return NO;
       }
    }
    return YES;
}
顺便说一句,如果你不期望超过20个首选项,它会更加务实,并将这些首选项硬编码为User(或Settings实体的正确命名属性如果你愿意,一对一的关系)。您的代码将非常易读,您的谓词相当简单。

答案 1 :(得分:0)

如果你想检查昵称是否已经存在,你可以尝试这样的事情(如果我理解你的模型是正确的)

NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:[NSEntityDescription entityForName:@"UserPreferences"
                                    inManagedObjectContext:context]];
[NSPredicate predicateWithFormat:@"Selection == %@ AND PreferenceTypes == 'nickname'", newUser.nickname]
NSArray *ary = [context executeFetchRequest:fetchRequest error:&err];

if(ary && ary.count > 0)
{
    // handle "user exists" case
}
else
{
    // handle "create user" case
}

我希望那就是你在寻找的东西。如果我理解你的问题是错误的或不起作用,请告诉我;)