【问题标题】:CoreData Many-to-Many Find DuplicatesCoreData 多对多查找重复项
【发布时间】:2015-05-06 06:58:54
【问题描述】:

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

用户>首选项

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

(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"

【问题讨论】:

  • UserPreferences 是您模型中的现有实体吗?很难看出你有什么混凝土。可能会添加您的模型或NSManagedObject 类的屏幕截图;)
  • 是的,它本质上是用户和偏好类型之间的连接表

标签: ios core-data join nspredicate predicate


【解决方案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 实体)的正确命名属性会更加实用关系,如果你愿意)。您的代码将非常易读,并且您的谓词相当简单。

【讨论】:

  • 添加了首选项检查示例。
【解决方案2】:

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

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
}

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

【讨论】:

  • 这个想法是做更多的连接。我正在寻找另一个用户具有相同偏好的 All 的场景。这些偏好本身是可变的。因此匹配的用户将具有相同的昵称、语言和所有其他首选项
猜你喜欢
  • 1970-01-01
  • 2018-03-11
  • 2021-03-14
  • 1970-01-01
  • 2012-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多