帮助CoreData查询 [英] Help with CoreData Query
问题描述
我正在寻找在CoreData中编写一些基本查询的方法,文档中没有示例。以下是我的查询:
- 我有一个费用对象,它有一个开支字段。
- 费用可以链接到ExpenseCategory对象。
- 费用类别可以仅定义费用的类别(例如Food),也可以具有单位费率(例如里程)。如果它只是名称,则费用值是费用对象中的开支,或者是费用类别中的费用。* / $>
- 由于费用到类别链接是可选的,最终费用将基于
- I have an Expense object and it has an expenseAmount field.
- Expense can be linked to an ExpenseCategory object.
- ExpenseCategory may just define the category for the expense (for eg Food) or it may have a unit rate (for eg Mileage). If it is just name, the expense value is the expenseAmount in Expense object else it is expenseAmount * unitRate in ExpenseCategory.
- Since Expense to Category link is optional, the final expense would be based on presence/absence of Category and the unit rate.
$ b
因此,用于计算总费用的SQL查询将是:
select
TOTAL(e.amount * IFNULL(c.rate,1))
来自EXPENSE e
LEFT OUTER join CATEGORY c on
e.category = c.id
如何做在CoreData中?
一个更简单的解决方案可能是在你的Expense类中实现另一个方法, / p>
例如
- (NSDecimalNumber *)calculatedExpenseAmount {
NSDecimalNumber * actualAmount = self.expenseAmount;
//伪代码开始
if(self.expenseCategory!= nil){
actualAmount = self.expenseAmount * self.expenseCategory.unitRate;
}
return actualAmount;
}
到我以前的答案。
如果你想避免拉入每个managed对象,你可以使用NSDictionary-result查询来取出expenseAmount和expenseCategory.unitRate的值。
- (NSDecimalNumber *)totalExpenses
{
//获取任何相关类别的所有费用金额和单位费率。
NSFetchRequest * request = ...;
[request setManagedObjectContext:< ...>];
[request setEntity:< ExpenseAccountDescription>];
[request setResultType:NSDictionaryResultType];
NSArray * props = [NSArray arrayWithObjects:@expenseAmount,@category.unitRate,nil];
[request setPropertiesToFetch:props];
NSArray * amount = [request executeRequest:...]
// amount是一个字典数组,每个字段都包含所需的属性值。
//循环并求和各个金额
NSDecimal * total = [[NSDecimalNumber zero] decimalNumber];
NSAutoreleasePool * pool = nil; // contains the mess
NSCalculationError err = NSCalculationNoError;
for(NSDictionary * result in quantities)
{
pool = [NSAutoreleasePool new];
NSDecimal newTotal = [[NSDecimalNumber zero] decimalNumber];
NSDecimalNumber * expenseAmount = [result valueForKeyPath:@expenseAmount];
NSDecimalNumber * unitRate = [result valueForKeyPath:@category.unitRate];
if(unitRate!= nil){
//进行单位速率乘法并累加结果总和
NSDecimal calculated = [[NSDecimalNumber zero] decimalNumber];
err = NSDecimalMultiply(& calculated,[expenseAmount decimalNumber],[unitRate decimalNumber],NSRoundBankers);
if(err == NSCalculationNoError){
err = NSDecimalAdd(& newTotal,total,calculated,NSRoundBankers);
}
}
else {
//只是将结果累加到总计
err = NSDecimalAdd(& newTotal,total,[expenseAmount decimalNumber ],NSRoundBankers);
}
//保留新的合计
NSDecimalCopy(& total,newTotal);
[pool drain];
}
return [NSDecimalNumber decimalNumberWithDecimal:total];
}
如果您有10000个费用条目,则此提取和计算可能需要少于1MB的RAM。仪器将是你的朋友测量。
I am looking for ways to write some basic queries in CoreData and there are not examples in the documentation. Following is my query:
So a SQL query to calculate total expenses would be :
select
TOTAL(e.amount * IFNULL(c.rate, 1))
from EXPENSE e
LEFT OUTER join CATEGORY c on
e.category = c.id
How can this be done in CoreData?
A simpler solution might be to implement another method on your Expense class that gives you the appropriately calculated amount.
E.g.
- (NSDecimalNumber *) calculatedExpenseAmount {
NSDecimalNumber *actualAmount = self.expenseAmount;
// Pseudo-code begins
if (self.expenseCategory != nil) {
actualAmount = self.expenseAmount * self.expenseCategory.unitRate;
}
return actualAmount;
}
I'm adding on to my previous answer.
If you want to avoid pulling in every managed object, you could use the NSDictionary-result query to just pull out the expenseAmount and expenseCategory.unitRate values.
- (NSDecimalNumber *) totalExpenses
{
// Fetch all of the expense amounts and unit rate of any related category.
NSFetchRequest *request = ...;
[request setManagedObjectContext:<...>];
[request setEntity:<ExpenseAccountDescription>];
[request setResultType:NSDictionaryResultType];
NSArray *props = [NSArray arrayWithObjects:@"expenseAmount", @"category.unitRate", nil];
[request setPropertiesToFetch:props];
NSArray *amounts = [request executeRequest:...];
// amounts is an array of dictionaries, each hold the desired property values.
// Loop and sum the individual amounts
NSDecimal *total = [[NSDecimalNumber zero] decimalNumber];
NSAutoreleasePool *pool = nil; // contain the mess
NSCalculationError err = NSCalculationNoError;
for (NSDictionary *result in amounts)
{
pool = [NSAutoreleasePool new];
NSDecimal newTotal = [[NSDecimalNumber zero] decimalNumber];
NSDecimalNumber *expenseAmount = [result valueForKeyPath:@"expenseAmount"];
NSDecimalNumber *unitRate = [result valueForKeyPath:@"category.unitRate"];
if (unitRate != nil) {
// do the unit rate multiplication and accumulate the result in the total
NSDecimal calculated = [[NSDecimalNumber zero] decimalNumber];
err = NSDecimalMultiply (&calculated, [expenseAmount decimalNumber], [unitRate decimalNumber], NSRoundBankers);
if (err == NSCalculationNoError) {
err = NSDecimalAdd (&newTotal, total, calculated, NSRoundBankers);
}
}
else {
// just accumulate the result in the total
err = NSDecimalAdd (&newTotal, total, [expenseAmount decimalNumber], NSRoundBankers);
}
// Keep the new total
NSDecimalCopy(&total, newTotal);
[pool drain];
}
return [NSDecimalNumber decimalNumberWithDecimal:total];
}
If you have 10000 expense entries, this fetch and calculation might take less than 1MB of RAM. Instruments would be your friend in measuring that.
这篇关于帮助CoreData查询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!