【问题标题】:CoreData fetch request for count of relation and group by another relation (m2n)CoreData 获取关系计数和按另一个关系分组的请求(m2n)
【发布时间】:2014-12-05 09:27:45
【问题描述】:

在我的 CoreData 模型中,我有一个使用中间实体建模的 n2n 关系:

Person [1<--] Person2Appointment [-->1] Appointment

Person2Appointment 实体如下所示:

@interface Person2Appointment : NSManagedObject

// attributes
@property (nonatomic, retain) NSNumber * participationState;

// relations
@property (nonatomic, retain) Person * person;
@property (nonatomic, retain) Appointment * appointment;
...
@end

(这两种关系也被建模为PersonAppointment 实体上的反向关系)

我想获取所有人过去约会的计数。

在 SQL 中它看起来像:

select count(fk_appointment), fk_person 
  from person2appointment t0
  left join appointment t1 on t0.fk_appointment = t1.pk
where t1.date < ...
group by fk_person;

我尝试通过以下方式对我的 fetch-request 使用计数函数表达式:

 // create a fetch request for the Person2Appointment entity (category method)
NSFetchRequest* fetch = [Person2Appointment fetchRequest];
fetch.resultType = NSDictionaryResultType;

// count appointments
NSExpression* countTarget = [NSExpression expressionForKeyPath: @"appointment"];
NSExpression* countExp = [NSExpression expressionForFunction:@"count:" arguments: @[countTarget]];
NSExpressionDescription* countDesc = [[NSExpressionDescription alloc]init];
countDesc.name=@"count";
countDesc.expression = countExp;
countDesc.expressionResultType =  NSDecimalAttributeType;

fetch.propertiesToFetch = @["person", countDesc];
fetch.propertiesToGroupBy = ["person"];

fetch.predicate = ...;

打开 SQL 日志后,似乎 core-data 执行了正确的语句:

SELECT t0.ZPERSON, COUNT( t0.ZAPPOINTMENT) 
  FROM ZPERSON2APPOINTMENT t0 
  JOIN ZAPPOINTMENT t1 ON t0.ZAPPOINTMENT = t1.Z_PK 
  WHERE  t1.ZSTARTDATE > ? GROUP BY  t0.ZPERSON 

但是结果数组中的字典不包含数字计数,而是一个约会实体:

Printing description of d:
{
    count = "0xd0000000000c0018 <x-coredata://BABCBD2E-05AB-4AA5-AC2B-2777916E4EDF/Appointment/p3>";
    person = "0xd0000000000c0016 <x-coredata://BABCBD2E-05AB-4AA5-AC2B-2777916E4EDF/Person/p3>";
}

这是核心数据中的错误吗?

我在这里做错了吗?

或者有其他方法可以实现吗?

【问题讨论】:

  • 嗨,在我看来,你的第一个错误是你在 SQL 模式而不是核心数据模式下思考。在核心数据中,您不需要 Person2Appointment 实体。(因为核心数据是关于实体(如对象)而不是关于表)。您可以拥有与约会实体具有多对多关系(呼叫约会)的人员实体,与多向关系人员约会具有相反的关系。
  • 不过,为了解决您当前的问题(根据您当前的数据模型),您的 Person2Appointment 将有一个(约会日期)或至少 Person2Appointment.appointment.date。您唯一需要做的就是获取所有 Person2Appointment 其指定日期已过的时间。
  • @OnikIV 是对的,理想情况下你应该改造你的应用程序。一旦你掌握了核心数据,它实际上比 SQLite 更容易使用。您不需要中介实体。
  • 感谢@OnikIV - 1. 该帖子显示了我实际模型的简化模型。关系本身也是量化的(具有草稿/公共/已批准标志),因此无法删除它。此外,iOS 的 AFAIK 核心数据无法直接对 m2m 进行建模。 2. 在这里获取所有约会只是为了计算它们不是矫枉过正吗?在我的应用程序的团队视图中,我只需要所有团队成员的约会计数。
  • 如果您将数据模型放在这里(在图表视图中),它将很容易为您提供帮助。

标签: ios objective-c core-data


【解决方案1】:

这在我看来就像 CoreData 中的一个错误,但经过一些实验,我认为您可以通过修改计数表达式来计算您的 Person2Appointment属性 来实现您想要的实体,而不是计算Appointment 关系(计数应该相同,因为关系是一对一的,除非你有空值?):

NSExpression* countTarget = [NSExpression expressionForKeyPath: @"participationState"];
NSExpression* countExp = [NSExpression expressionForFunction:@"count:" arguments: @[countTarget]];

如果您确实需要担心 null 值,您可以使用:

NSExpression *countTarget = [NSExpression expressionForEvaluatedObject];

【讨论】:

  • 我花了一些时间才回到它,但我现在可以验证它,是的,将目标表达式更改为 expressionForEvaluatedObject 成功了 - 非常感谢!
【解决方案2】:

我只是在此尝试,但您可能会在尝试子查询时找到一些运气

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SUBQUERY(durationMinutes, $a, $a.date < %@)", someDate);
NSInteger count = [managedObjectContext countForEntityForName:@"Person2Appointment" predicate:predicate error:&error];

【讨论】:

  • 谢谢@Erik,但我不需要单个计数,我需要每个人的计数,是的,我想在单个请求中获取它,就像您对数据库的期望一样.我知道如何遍历所有人并计算每个人的约会,这不是这里的问题。我正在尝试将聚合函数与一个组一起使用,该组似乎并不真正适用于关系实体......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-10
  • 1970-01-01
  • 1970-01-01
  • 2018-01-02
  • 2023-03-10
  • 2015-03-13
相关资源
最近更新 更多