CoreData 多对多查找重复项

CoreData Many-to-Many Find Duplicates

我正在研究一个谓词来搜索与任何其他用户具有相同偏好的用户

用户 <<->> 首选项

给定以下状态;我想查询新注册用户

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

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

用户

| Name  |
| Sally |
| John  |

偏好类型

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

用户首选项

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

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

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
}

我希望这就是您要找的。如果我对你的问题的理解有误或者它不起作用,请告诉我 ;)

您可以这样设置模型:

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

您的谓词将需要一个子查询,并且在资源使用方面相当 "expensive"。我假设允许某些用户拥有其他用户没有的偏好,即虽然我们知道可能偏好的总数,但我们不知道某个特定用户拥有的偏好数量。我不能从头顶写出那个查询,我必须考虑一下。 --- 有人吗?

一种实用的方法是首先获取用户的一个子集,比如说那些昵称完全相同的用户。使用像这样的谓词获取偏好对象会更简单:

[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 的实体如果您愿意,可以建立一对一的关系)。您的代码将非常可读,并且您的谓词相当微不足道。