2010-11-26 12 views
3

私のアプリケーションには、スマートフォルダのような機能があります:述語はNSPredicateEditorで設定され、フェッチ要求でフォルダを埋めるために使用されます。コアデータは '順序付けされた'関係のプロパティに基づいてフェッチされます

検索に使用されるエンティティには多対多の関係があります。この関係は、並べ替えの目的でインデックスが宛先エンティティに格納されるという意味で、順序付けられます。

私の問題は、順序付けされた関係の最後の値に基づいてルールを構築したいのですが、関係が配列ではないため、これを行うための述語を作成する方法を理解できません。コアデータは実際には順序を知らない。

注文アイテムを返すクラスにreadonlyプロパティがありますが、このプロパティはコアデータストアで使用できないため、フェッチ要求に役立たないようです。

私が考えることができる唯一の選択肢は、別のプロパティで順序付けられた関係の最後の項目を非正規化して保存することです。それが唯一の解決策ですか?

答えて

1

nの結果は、フェッチ要求レベルでのみ述語になるとは限りません。

あなたが言及したように、関係の最後のn個のアイテムを参照するのとは別に、ブール値属性 "lastN"を試して、リストの順序をキュレートするときにそれらを反転させることができます(例えば、ドラッグアンドドロップによる並べ替え)。

また、ソートキーで並べ替え、降順に並べ替えられ、-setFetchLimit:を介してnの結果に制限されている、検索されたものごとに別々のフェッチ要求を作成できます。

これを関係または属性として追跡することはやや面倒ですが、フェッチ制限は(複数回の往復のため)より高額です。あなたの並べ替えが一回限りのユーザーアクションによって行われた場合、一連のフェッチですべてを一度に行うのではなく、償却されるので、関係や属性のアプローチを使用する方がパフォーマンスが向上します。私は自分自身でより良い方法を見つけていないし、この1つに密接に従います。 :-)

+0

私は、1つの述語的なフェッチでそれを行うことができることを望んでいましたが、私はそれができないと考え始めています。私は余分なプロパティ - 非正規化 - を使用しているという感覚が、おそらく、パフォーマンス上の賢明な方法です。 –

+0

確かに、オブジェクトごとに検索される1フェッチ要求のアプローチは、検索対象のリストが大量であれば無駄で無駄ですが、小さなリストの場合は合理的なヒットになる可能性があります。私は個人的に "lastN"フラグアプローチを使用します。私は(私を引用しないで)関係は、自動的にコアデータを使った複数のラウンドトリップを意味すると思います。 –

2

私が問題を正しく理解しているとすれば、私はこのようにします。 TopEntityに(NSString *)の名前プロパティと(NSString *)データプロパティと(NSInteger)orderプロパティを持つMyEntityとの関係があります。

あなたが与えられた文字列に一致するTopEntityオブジェクトをしたいと言うと、そのMyEntity注文後、あなたはそう....

NSManagedObjectContext *context = [self managedObjectContext]; 

// Create some top level entities 
TopEntity *aTop = [TopEntity insertInManagedObjectContext:context]; 
aTop.name = @"This is Your Name"; 
TopEntity *bTop = [TopEntity insertInManagedObjectContext:context]; 
bTop.name = @"This aint a Name";  
TopEntity *cTop = [TopEntity insertInManagedObjectContext:context]; 
cTop.name = @"This is My Name";  

// Add some data 
NSInteger i, len = 30; 
for(i=0; i<len; i++) { 
    // Create a new object 
    MyEntity *entity = [MyEntity insertInManagedObjectContext:context]; 
    entity.orderValue = i; 
    entity.data = [NSString stringWithFormat:@"This is some data: %d", i]; 
    if(i < 10) { 
     [aTop addObjectsObject:entity]; 
     [entity addTopObject:aTop]; 
    } else if (i < 20) { 
     [bTop addObjectsObject:entity]; 
     [entity addTopObject:bTop];    
    } else { 
     [cTop addObjectsObject:entity]; 
     [entity addTopObject:cTop];       
    } 
} 

// Save the context 
NSError *error = nil; 
[context save:&error]; 

// A predicate to match against the top objects 
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name BEGINSWITH %@", @"This is"]; 
// A predicate to match against the to-many objects 
NSPredicate *secondPredicate = [NSPredicate predicateWithFormat:@"ANY objects.order < %d", 5]; 
NSFetchRequest *fetch = [[NSFetchRequest alloc] init]; 
[fetch setEntity:[NSEntityDescription entityForName:@"TopEntity" inManagedObjectContext:context]]; 
[fetch setPredicate:predicate]; 
NSArray *result = [[context executeFetchRequest:fetch error:&error] filteredArrayUsingPredicate:secondPredicate]; 


for(TopEntity *entity in result) { 
    NSLog(@"entity name: %@", entity.name);   
} 
ように二つの述語とNSFetchRequestでそれを行うことができ、一定の条件を満たしていることができます

基本的に、フェッチ要求の結果を別の述部で囲み、ANYキーワードを使用するだけで済みます。

私はそれがいかに効率的であるか分かりませんが、この場合はうまくいきます。上記を実行すると「This is Your Name」と表示されます。つまり、最初のTopEntityに一致します。

+0

なぜ私はこれについて考えなかったのか分かりませんが、それはさらに簡単です。 @ "(name BEGINSWITH%@)AND(ANY objects.order>%d)のような形式の述語を使用してください。 orderプロパティの等価性は、あなたが望むものに依存します.n-recent-to-manyオブジェクトのデータに基づいて結果を制限したいのか、n-recentオブジェクトだけに制限するのかはわかりません。 NSPredicate形式の文字列ドキュメントは非常に便利です:http://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/Predicates/Articles/pSyntax.html%23//apple_ref/doc/uid/ TP40001795-CJBDBHCB –

+0

ええ、注文指数を使用する最後の解決法は、実際にはかなり良いです。私が持っているいくつかのケースで確かに働くことができました。ありがとう!オリジナルのソリューションも良いですが、単一の述語で検索する私の一般的な「スマートフォルダ」アプローチにはうまく収まりません。 –

関連する問題