Iphone 核心数据“;“向上插入”;从SQLite数据库
我目前正在编写一个应用程序,需要能够修改和保存各种数据。我已决定为此目的使用核心数据。 当用户第一次打开应用程序时,我需要从sqlite数据库导入大量数据,这些数据由多对多关系组成 我想找出将所有这些数据插入代码数据存储的最佳方法。现在,我正在使用NSOperation在应用程序的其余部分保持活动状态的情况下进行导入,这样用户可以做其他事情,但我希望导入能够尽快进行,以便可以立即访问整个应用程序 我现在使用的方法是使用NSFetchRequest尝试在数据存储中查找相关实体,如果实体在那里,我只是将其作为关系添加,如果实体不在那里,我创建一个新实体并将其作为关系添加。这是可行的,但我觉得它可能还没有接近最佳状态 我现在使用的代码是:Iphone 核心数据“;“向上插入”;从SQLite数据库,iphone,sqlite,core-data,embedded-database,upsert,Iphone,Sqlite,Core Data,Embedded Database,Upsert,我目前正在编写一个应用程序,需要能够修改和保存各种数据。我已决定为此目的使用核心数据。 当用户第一次打开应用程序时,我需要从sqlite数据库导入大量数据,这些数据由多对多关系组成 我想找出将所有这些数据插入代码数据存储的最佳方法。现在,我正在使用NSOperation在应用程序的其余部分保持活动状态的情况下进行导入,这样用户可以做其他事情,但我希望导入能够尽快进行,以便可以立即访问整个应用程序 我现在使用的方法是使用NSFetchRequest尝试在数据存储中查找相关实体,如果实体在那里,我只
- (void)importEntitiesIntoContext: (NSManagedObjectContext*)managedObjectContext
{
// Setup the database object
static NSString* const databaseName = @"DBName.sqlite";
NSString* databasePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent: databaseName];
sqlite3* database;
// Open the database from the user's filessytem
if ( sqlite3_open_v2( [databasePath UTF8String], &database, SQLITE_OPEN_READONLY, NULL ) == SQLITE_OK )
{
// Setup the SQL Statement
NSString* sqlStatement = [NSString stringWithFormat: @"SELECT some_columns FROM SomeTable;"];
sqlite3_stmt* compiledStatement;
if ( sqlite3_prepare_v2( database, [sqlStatement UTF8String], -1, &compiledStatement, NULL ) == SQLITE_OK )
{
// Create objects to test for existence of exercises
NSPredicate* predicate = [NSPredicate predicateWithFormat: @"something == $SOME_NAME"];
NSEntityDescription* entityDescription = [NSEntityDescription entityForName: @"SomeEntity"
inManagedObjectContext: managedObjectContext];
NSFetchRequest* fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
[fetchRequest setEntity: entityDescription];
// Loop through the results and add them to the feeds array
while ( sqlite3_step( compiledStatement ) == SQLITE_ROW )
{
NSString* someName = [NSString stringWithCharsIfNotNull: (char*)sqlite3_column_text( compiledStatement, 1 )];
NSPredicate* localPredicate = [predicate predicateWithSubstitutionVariables:
[NSDictionary dictionaryWithObject: someName
forKey: @"SOME_NAME"]];
[fetchRequest setPredicate: localPredicate];
NSError* fetchError;
NSArray* array = [managedObjectContext executeFetchRequest: fetchRequest
error: &fetchError];
if ( array == nil )
{
// handle error
}
else if ( [array count] == 0 )
{
SomeEntity* entity =
[NSEntityDescription insertNewObjectForEntityForName: @"SomeEntity"
inManagedObjectContext: managedObjectContext];
entity.name = someName;
// **here I call a method that attempts to add the relationships(listed below)**
}
else
{
// Some entity already in store
}
}
}
else
{
NSLog( @"sqlStatement failed: %@", sqlStatement );
}
// Release the compiled statement from memory
sqlite3_finalize( compiledStatement );
}
// All the data has been imported into this temporary context, now save it
NSError *error = nil;
if ( ![managedObjectContext save: &error] )
{
NSLog( @"Unable to save %@ - %@", [error localizedDescription] );
}
}
方法来添加关系:
- (void)setRelationshipForEntity: (Entity*)entity
inManagedObjectContext: (NSManagedObjectContext*)managedObjectContext
usingDatabase: (sqlite3*)database
entityId: (NSNumber*)entityId
{
// Setup the SQL Statement and compile it for faster access
NSString* sqlStatement = [NSString stringWithFormat: @"SELECT Relationship.name FROM Relationship JOIN Entitys_Relationship ON Entitys_Relationship.id_Relationship = Relationship.id JOIN Entitys ON Entitys_Relationship.id_Entitys = Entitys.id WHERE Entitys.id = %d;", [entityId integerValue]];
sqlite3_stmt* compiledStatement;
if ( sqlite3_prepare_v2( database, [sqlStatement UTF8String], -1, &compiledStatement, NULL ) == SQLITE_OK )
{
// Create objects to test for existence of relationship
NSPredicate* predicate = [NSPredicate predicateWithFormat: @"relationshipName == $RELATIONSHIP_NAME"];
NSEntityDescription* entityDescription = [NSEntityDescription entityForName: @"EntityRelationship"
inManagedObjectContext: managedObjectContext];
NSFetchRequest* fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
[fetchRequest setEntity: entityDescription];
while ( sqlite3_step( compiledStatement ) == SQLITE_ROW )
{
NSString* relationshipName = [NSString stringWithCharsIfNotNull: (char*)sqlite3_column_text( compiledStatement, 0 )];
NSPredicate* localPredicate = [predicate predicateWithSubstitutionVariables:
[NSDictionary dictionaryWithObject: relationshipName
forKey: @"RELATIONSHIP_NAME"]];
[fetchRequest setPredicate: localPredicate];
NSError* fetchError;
NSArray* array = [managedObjectContext executeFetchRequest: fetchRequest
error: &fetchError];
if ( array == nil )
{
// handle error
}
else if ( [array count] == 0 )
{
EntityRelationship* entityRelationship =
[NSEntityDescription insertNewObjectForEntityForName: @"EntityRelationship"
inManagedObjectContext: managedObjectContext];
entityRelationship.relationshipName = relationshipName;
[entity addRelationshipObject: entityRelationship];
//NSLog( @"Inserted relationship named %@", relationshipName );
}
else
{
[entity addRelationship: [NSSet setWithArray: array]];
}
}
}
else
{
NSLog( @"slqStatement failed: %@", sqlStatement );
}
// Release the compiled statement from memory
sqlite3_finalize( compiledStatement );
}
原始数据库来自哪里
通常,在开发过程中,您会将所有数据转换为核心数据,然后随附预填充的核心数据存储(用户无需等待导入)。苹果对如何优化核心数据存储中的大型导入提出了一些建议:
- 在批导入期间禁用撤消管理器
- 不逐个记录插入记录-创建大小为n的批(取决于记录大小)
- 使用本地自动释放池,并在每次批处理后将其排空
有关详细信息,请参阅。信息位于sqlite数据库中,用户将能够更改其个人设备上的信息,但对于应用程序更新,数据将需要与新数据合并。我仍将保留该数据,以便合并在设备上的用户核心数据存储和应用程序更新的初始核心数据存储之间,但这是因为我更喜欢使用核心数据。您通常使用什么方法创建初始CoreData存储?我将使用相同的数据模型制作一个简单的mac应用程序来导入和保存初始核心数据SQLite文件。然后,我将把该文件添加到iPhone应用程序项目中。在第一次运行时,它将作为用户的核心数据文件进行复制。对于升级,还将添加更新对象的另一个核心数据文件,并逐个检查,以便不使用用户更新覆盖对象。我的导入是通过来自web应用程序的JSON响应进行的,因为我们的所有数据都在web数据库中。您应该使用最有意义的方法——听起来您的导入将来自SQLite数据库。您使用什么方法检查对象以防止覆盖?这是我的主要问题。你基本上是在做我上面所做的,还是你有更好的方法?