首页 文章

预加载具有多对多关系的核心数据的最佳实践

提问于
浏览
1

我正在开发一个具有核心数据的IOS应用程序,我必须预先加载与核心数据有很多关系的数据 . 我有三个 table ,超市,产品和中间表名为supermarketToproduct,存储超市与产品之间的关系 . 正如我所说,超市和产品实体之间存在多对多的关系,因此我需要创建一个中间表来表明关系 . 我的问题是,将JSON格式的数据预加载到具有多对多关系的核心数据中的最佳做法是什么 . 在Apples参考文档中,声明不需要创建中间表,因为coredata为我们创建了一个 . 但是,如何在没有中间表的情况下预加载日期时如何定义多对多关系?顺便说一句,所有数据都是静态的,所以不需要将新数据插入表中,我只需要获取数据及其相关的超市或产品 . 请注意,连接表有两个独立的属性,名为priceofProductforGivenMarket和primaryProductforGivenMarket这是我的数据的JSON表示,也是我将在核心数据中创建的模型:

Supermarket:
name
location
phone number

Product:
name
price
company

supermarketToproduct:
 nameofsupermarket
 nameofproduct 
 priceofProductforGivenMarket
 primaryProductforGivenMarket

2 回答

  • 1

    我将创建三个实体,Supermarket,Product和SupermaketProductDetails,其属性和关系如下:

    Supermarket:
    Attributes: name, location, phone number
    Relationship (to many): productDetails
    
    Product:
    Attributes: name, price, company
    Relationship (to many): supermarketDetails
    
    SupermarketProductDetails:
    Attributes:  priceofProductforGivenMarket, primaryProductforGivenMarket
    Relationships: (to one) supermarket, (to one) product
    

    在Xcode中,指示超市实体中productDetails关系的“目的地”是SupermarketProductDetails实体,使用逆超市,同样将SupermarketProductDetails实体设置为Product实体中的supermarketDetails的目的地,具有逆产品 .

    然后我会首先解析超市的JSON数据,创建超市对象并设置名称,位置和电话号码,但不输入产品关系的任何内容 . 同样,解析产品JSON并创建所有Products对象 . 然后我将解析连接表,并创建SupermarketProductDetails对象 . 根据您的JSON数据设置属性,并执行获取以获取具有正确名称的超市实体,同样获取具有正确名称的Product实体,然后直接设置这些关系 .

    EDIT: 假设您将连接表中的每一行解析为四个NSStrings:nameofsupermarket,nameofproduct,priceofProductforGivenMarket和primaryProductforGivenMarket . 那么对于每一行......

    // First fetch the correct Supermarket...
    NSFetchRequest *supermarketFetch = [NSFetchRequest fetchRequestWithEntityName:@"Supermarket"]
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name like %@",nameofsupermarket];
    supermarketFetch.predicate = predicate;
    NSError *error;
    NSArray *results = [context executeFetchRequest:supermarketFetch error:&error];
    // should really check for errors, and that we get one and only one supermarket
    NSLog(@"Supermarket fetch returned %i results",[results count]);  // should be only 1!
    mySupermarket = (NSManagedObject *)[results firstObject];
    if (![[mySupermarket valueForKey:@"name"] isEqualToString:nameofsupermarket]) {
        NSLog(@"Wrong supermarket fetched");
        }
    
    // Now fetch the product...
    NSFetchRequest *productFetch = [NSFetchRequest fetchRequestWithEntityName:@"Product"]
    predicate = [NSPredicate predicateWithFormat:@"name like %@",nameofproduct];
    productFetch.predicate = predicate;
    results = [context executeFetchRequest:productFetch error:&error];
    // should really check for errors, and that we get one and only one product
    NSLog(@"Product fetch returned %i results",[results count]);  // should be only 1!
    myProduct = (NSManagedObject *)[results firstObject];
    if (![[myProduct valueForKey:@"name"] isEqualToString:nameofproduct]) {
        NSLog(@"Wrong product fetched");
        }
    
    // Now create the SupermarketProductDetails entity:
    NSManagedObject *mySupermarketProductDetails = [NSEntityDescription insertNewObjectForEntityForName:@"SupermarketProductDetails" inManagedObjectContext:context];
    // set attributes...
    [mySupermarketProductDetails setValue:primaryProductForGivenMarket forKey:@"primaryProductForGivenMarket"];
    [mySupermarketProductDetails setValue:priceOfProductForGivenMarket forKey:@"priceOfProductForGivenMarket"];
    // set relationships...
    [mySupermarketProductDetails setValue:mySupermarket forKey:@"supermarket"];
    [mySupermarketProductDetails setValue:myProduct forKey:@"product"];
    [context save:&error];
    // should check for errors...
    

    请注意,您只需要设置这些关系的一面--CoreData为您更新另一面(即它将mySupermarketDetails添加到myProduct的supermarketDetails集等) . 还要注意,(一对一)关系(例如超市)的“ Value ”是目标对象本身(例如mySupermarket);你不要使用名称或任何其他密钥 . Coredata(隐藏在底层的sql表中)使用唯一的objectID来进行链接 .

    (这可能是更有效的方法,而不是为每个SupermarketProductDetails条目进行两次提取,但这将有效 . )

    EDIT2:请注意,上面假设您的实体都是作为NSManagedObjects实现的 . 如果您为每个实体创建了单独的子类,那么您可以简化上面的一些代码 . 例如,valueForKey:和setValue:forKey:可以使用点表示法替换为等效的属性访问器方法,例如:

    [mySupermarketProductDetails setValue:primaryProductForGivenMarket forKey:@"primaryProductForGivenMarket"];
    

    会成为:

    mySupermarketProductDetails.primaryProductForGivenMarket = primaryProductForGivenMarket;
    

    [mySupermarket valueForKey:@"name"]
    

    可以替换为:

    mySupermarket.name
    

    同样,应使用适当的子类而不是NSManagedObject创建对象 . 例如 .

    NSManagedObject *mySupermarketProductDetails = [NSEntityDescription insertNewObjectForEntityForName:@"SupermarketProductDetails" inManagedObjectContext:context];
    

    会成为

    SupermarketProductDetails *mySupermarketProductDetails = [NSEntityDescription insertNewObjectForEntityForName:@"SupermarketProductDetails" inManagedObjectContext:context];
    
  • 1

    我认为上面的方法很难预取,并且会预取几乎所有匹配的条目,并且预取的真正动机将会消失 .

    我还建议在超市表中添加topProduct .

    您必须在两个方向上定义多对多关系 - 也就是说,您必须指定两个关系,每个关系都是另一个关系的倒数

    Edit 01:

    Product (Attributes):
    name
    price
    company
    
    Supermarket (Attributes):
    name
    location
    phone number
    supermarket top Product
    

    一旦你创建了类似上面的属性并添加了多对多的关系 .

    Coredata将在下面添加 relationships 的相应实体 .

    **NSSet products, [supermarket table] and NSSet supermarkets [product table]**
    

    所以现在你可以在插入数据之后实际更新这种关系:即

    Insert

    // Create Product
        NSManagedObject *product = [[NSManagedObject alloc] initWithEntity:@"Product" insertIntoManagedObjectContext:self.managedObjectContext];
    
        // Set details
        [product setValue:@"xxx" forKey:@"name"];
        ...
    
    // Create Supermarket
    
        NSManagedObject *supermarket = [[NSManagedObject alloc] initWithEntity:@"SuperMarket" insertIntoManagedObjectContext:self.managedObjectContext];
    
        // Set First and Last Name
        [supermarket setValue:@"Main Street" forKey:@"name"];
        ...
    
    // Create Relationship
    
        [supermarket setValue:[NSSet setWithObject:product] forKey:@"products"];
    
        // Save Managed Object Context
        NSError *error = nil;
        if (![supermarket.managedObjectContext save:&error]) {
            NSLog(@"Unable to save managed object context.");
            NSLog(@"%@, %@", error, error.localizedDescription);
        }
    
    //And similarly inverse relationship.
    

    Fetching

    此外,由于您在超市表中有关于产品的相关信息,反之亦然,因此提取将是平滑的之前讨论过,不会预先预取所有数据,否则它会做 . 因为没有必要通过coreData fetch创建进一步的关系 .

    Please follow for more details: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreData/Articles/cdRelationships.html#//apple_ref/doc/uid/TP40001857-SW10

    另请注意:Core Data sectionNameKeyPath with Relationship Attribute Performance Issue

相关问题