2011-01-20 3 views
5

CoreData에서 몇 가지 기본 쿼리를 작성하는 방법을 찾고 있는데 설명서에는 예제가 없습니다. 다음은 내 검색어입니다.CoreData 쿼리에 대한 도움말

  1. 나는 Expense 개체가 있으며 비용 지출 필드가 있습니다.
  2. 비용을 ExpenseCategory 개체에 연결할 수 있습니다.
  3. ExpenseCategory는 비용 (예 : Food)의 카테고리를 정의하거나 단위 요금 (예 : 마일리지)을 정의 할 수 있습니다. 이름이 단순한 경우 비용 값은 Expense 객체의 expenseAmount이고 ExpenseCategory에서는 expenseAmount * unitRate입니다.
  4. 비용 지출은 카테고리 링크가 선택 사항이므로 최종 지출은 카테고리의 유무와 단위 요율에 따라 결정됩니다.

그래서 총 비용을 계산하는 SQL 쿼리은 다음과 같습니다이는 CoreData에

select 
    TOTAL(e.amount * IFNULL(c.rate, 1)) 
from EXPENSE e 
LEFT OUTER join CATEGORY c on 
    e.category = c.id 

을 수행 할 수 있습니까?

+0

이 질문에 감사드립니다. 나도 비슷한 문제가 있고 NSExpression이 나에게 도움이 안된다. 나는 double과 timestamp를 가지고 일하고 있는데 어떤 이유로 divide : by : 함수가 이상한 결과를 만든다. 내 계산에 하나 이상의 레코드를 포함해야하므로 최종 솔루션이 궁금합니다. –

답변

2

더 간단한 해결책은 적절하게 계산 된 금액을 제공하는 Expense 클래스에 다른 방법을 구현하는 것일 수 있습니다.

예.

- (NSDecimalNumber *) calculatedExpenseAmount { 

    NSDecimalNumber *actualAmount = self.expenseAmount; 

    // Pseudo-code begins 
    if (self.expenseCategory != nil) { 
    actualAmount = self.expenseAmount * self.expenseCategory.unitRate; 
    } 

    return actualAmount; 
} 

내 이전의 대답에 추가 해요.

모든 관리 객체를 가져 오지 않으려면 NSDictionary-result 쿼리를 사용하여 expenseAmount 및 expenseCategory.unitRate 값을 추출하면됩니다.

- (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]; 
} 

비용 항목이 10000 개일 경우이 가져 오기 및 계산에 1MB 미만의 RAM이 필요할 수 있습니다. 인스 트루먼 트가 그것을 측정하는 당신의 친구가 될 것입니다.

+0

이것은 단일 비용으로 효과가 있습니다. 나는 메모리에있는 모든 것을 읽지 않고 DB의 모든 비용을 대조하려고합니다. – siasl

+0

도움을 주셔서 감사합니다. NSExpression 클래스의 multiply : by :를 사용하여 sqlite 자체에서이 계산을 수행하려고 시도했습니다. 시뮬레이터에서 RT 예외가 발생했으며 아직 iPhone에서 사용할 수 없다고 생각합니다. 여기서 내가 이해하지 못하는 것은 CoreData가 그렇게 간단한 것을지지하지 않는 이유입니다. 예, 나는 CD가 객체 그래프의 측면에서 생각하고 결국 데이터에 관한 것이라고 생각합니다. – siasl

+0

저는 CD가 임의의 SQL을 실행할 수있는 방법이 없다고 확신합니다. 정말로 끈기가 있다면 SQLite로 직접 갈 수도 있습니다. 그것은 당신이하고 싶은 모든 것을 지원합니다. –