简体   繁体   English

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

[英]Best practice for preloading core data with many to many relationship

I am developing an IOS application which has core data and I have to preload data many to many relationship to the core data. 我正在开发一个具有核心数据的IOS应用程序,我必须预加载与核心数据多对多关系的数据。 I have three tables with supermarket, product and intermediate table called supermarketToproduct which stores the relationship between supermarkets to products. 我有三个表,其中包含超级市场,产品和称为超级市场的​​中间表,该中间表存储了超级市场与产品之间的关系。 As I stated, there is many to many relationship between supermarket and product entities hence I needed to create an intermediate table to indicate the relationships. 正如我所说,超市和产品实体之间存在许多关系,因此我需要创建一个中间表来指示这些关系。 My question is that what is the best practice to preload JSON formatted data into my core data with many to many relationship. 我的问题是,以多对多关系将JSON格式的数据预加载到我的核心数据中的最佳实践是什么。 In Apples reference documents, it is stated that there is no need to create intermediate table as coredata creates one for us. 在Apples参考文档中,声明了无需创建中间表,因为coredata为我们创建了一个中间表。 However, How can I define many to many relationship while preloading the date without intermediate table? 但是,如何在不带中间表的情况下预加载日期时定义多对多关系? By the way, all the data is static so no need to insert new data into tables, I only need fetch the data and its related supermarket or product. 顺便说一下,所有数据都是静态的,因此无需在表中插入新数据,我只需要获取数据及其相关的超级市场或产品。 Please note that joined table has two independent attributes called priceofProductforGivenMarket and primaryProductforGivenMarket Here is the JSON representation of my data, also it is the model that I would create in core data: 请注意,联接表具有两个独立的属性,分别称为priceofProductforGivenMarket和primaryProductforGivenMarket。这是数据的JSON表示形式,也是我将在核心数据中创建的模型:

Supermarket:
name
location
phone number

Product:
name
price
company

supermarketToproduct:
 nameofsupermarket
 nameofproduct 
 priceofProductforGivenMarket
 primaryProductforGivenMarket

I think the above approach would be hard on prefetching and would prefetch almost all matching entries and the real motive of prefetch would be gone. 我认为上述方法很难预取,并且几乎可以预取所有匹配的条目,并且预取的真正动机已经消失了。

also I would suggest to add topProduct in Supermarket table. 我也建议在超市表中添加topProduct。

You must define many-to-many relationships in both directions—that is, you must specify two relationships, each being the inverse of the other 您必须在两个方向上定义多对多关系-也就是说,您必须指定两个关系,每个关系都是彼此相反的

Edit 01: 编辑01:

Product (Attributes):
name
price
company

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

Once you create Attributes like above and add the many to many relationship. 一旦创建了上述属性并添加了多对多关系。

Coredata will add below to the respective entity for relationships . Coredata将在下面添加到各个实体的关系

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

So now you can actually update this relationship after inserting the data as bellow: ie 因此,现在您可以在按以下方式插入数据之后实际更新此关系:

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

also now since you have related information about product in Supermarket table and vice versa, the fetching will be smoothing and as discussed before, will not prefetch all data upfront which it would have done otherwise. 同样,由于您已经在Supermarket表中获得了有关产品的相关信息,反之亦然,因此获取将变得很平滑,并且如前所述,不会预先提取所有本来可以完成的数据。 As there is no need to create further relationship by coreData fetch. 由于无需通过coreData获取来创建进一步的关系。

Please follow for more details: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreData/Articles/cdRelationships.html#//apple_ref/doc/uid/TP40001857-SW10 请遵循以获取更多详细信息: https : //developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreData/Articles/cdRelationships.html#//apple_ref/doc/uid/TP40001857-SW10

Also Please follow this: Core Data sectionNameKeyPath with Relationship Attribute Performance Issue 另外,请按照以下步骤操作: 具有关系属性性能问题的核心数据sectionNameKeyPath

I would create three entities, Supermarket, Product and SupermaketProductDetails, with attributes and relationships as follows: 我将创建三个实体,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

In Xcode, indicate that the "destination" for the productDetails relationship in the Supermarket entity is the SupermarketProductDetails entity, with inverse supermarket, likewise set the SupermarketProductDetails entity as the destination for the supermarketDetails in the Product entity, with inverse product. 在Xcode中,指示Supermarket实体中productDetails关系的“目的地”是SupermarketProductDetails实体(具有反向超级市场),同样,将SupermarketProductDetails实体设置为Product实体中具有反向产品的超级市场细节的目的地。

Then I would parse your JSON data for supermarkets first, creating Supermarket objects and setting the name, location and phone number but without entering anything for the products relationship. 然后,我将首先为超级市场解析您的JSON数据,创建超级市场对象并设置名称,位置和电话号码,但无需为产品关系输入任何内容。 Likewise, parse the products JSON and create all the Products objects. 同样,解析产品JSON并创建所有Products对象。 Then I would parse the join table, and create the SupermarketProductDetails objects. 然后,我将解析联接表,并创建SupermarketProductDetails对象。 Set the attributes based on your JSON data, and execute a fetch to get the Supermarket entity with the right name, likewise fetch the Product entity with the right name, and then set these relationships directly. 根据您的JSON数据设置属性,并执行获取操作以获取具有正确名称的Supermarket实体,同样获取具有正确名称的Product实体,然后直接设置这些关系。

EDIT: Assume that you parse each line in your join table into four NSStrings: nameofsupermarket, nameofproduct, priceofProductforGivenMarket and primaryProductforGivenMarket. 编辑:假定您将联接表中的每一行解析为四个NSStrings:超级市场名称,产品名称,priceforGivenMarket的价格和primaryProductforGivenMarket。 Then for each line... 然后每行...

// 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...

Note that you only need to set one side of these relationships - CoreData updates the other side for you (ie it will add mySupermarketDetails to the set of supermarketDetails for myProduct, etc). 请注意,您只需要设置这些关系的一侧-CoreData会为您更新另一侧(即它将mymymarketDetails添加到myProduct的超级市场详细信息集中,等等)。 Note also that the "value" for a (to-one) relationship (eg supermarket) is the destination object itself (eg mySupermarket); 还请注意,(一对一)关系(例如,超级市场)的“值”是目标对象本身(例如,mySupermarket); you don't use the name or any other key. 您不使用名称或其他任何键。 Coredata is (hidden in the underlying sql tables) using unique objectIDs to do the linking up. Coredata(隐藏在基础sql表中)使用唯一的objectID进行链接。

(There are probably more efficient means of doing this, rather than doing two fetches for every SupermarketProductDetails entry, but this will work.) (执行此操作可能有更有效的方法,而不是对每个SupermarketProductDetails条目进行两次访存,但这是可行的。)

EDIT2: Note that the above assumes that your entities are all implemented as NSManagedObjects. EDIT2:请注意,以上假设您的实体都被实现为NSManagedObjects。 If you have created separate subclasses for each entity, then you can simplify some of the above code. 如果为每个实体创建了单独的子类,则可以简化上面的一些代码。 For example, valueForKey: and setValue:forKey: can be replaced by the equivalent property accessor methods using dot notation, eg.: 例如,valueForKey:和setValue:forKey:可以用点表示法替换为等效的属性访问器方法,例如:

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

would become: 会成为:

mySupermarketProductDetails.primaryProductForGivenMarket = primaryProductForGivenMarket;

and

[mySupermarket valueForKey:@"name"]

can be replaced by: 可以替换为:

mySupermarket.name

Likewise, objects should be created with the appropriate subclass rather than NSManagedObject. 同样,应使用适当的子类而不是NSManagedObject创建对象。 eg. 例如。

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

would become 会成为

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM