FROM : Pierre Bernard
DATE : Tue Nov 06 21:17:52 2007
Adam,
Thanks for clarifying this. I can find no word about this in the
documentation. This is a very serious limitation and should be
mentioned.
Is there really no way to infer entity hashes from the tables
available in the SQLite store at hand?
Wouldn't it be great if one could specify a default legacy model to
use on Tiger files?
Would you consider the below code to be preferable to the workaround I
posted earlier?
NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator
metadataForPersistentStoreOfType:NSSQLiteStoreType URL:url error:error];
if (sourceMetadata == nil)
{
return NO;
}
id versionHashes = [sourceMetadata
objectForKey:@"NSStoreModelVersionHashes"];
BOOL ok = NO;
if (versionHashes != nil) {
NSMutableDictionary *newStoreOptions;
if (storeOptions == nil)
{
newStoreOptions = [NSMutableDictionary dictionary];
}
else
{
newStoreOptions = [[storeOptions mutableCopy] autorelease];
}
[newStoreOptions setObject:[NSNumber numberWithBool:YES]
forKey:NSMigratePersistentStoresAutomaticallyOption];
ok = [super configurePersistentStoreCoordinatorForURL:url
ofType:fileType
modelConfiguration:configuration
storeOptions:newStoreOptions
error:error];
}
else {
NSURL *modelURL = [NSURL fileURLWithPath:[Document
pathForModelNamed:@"HoudahSpot"]];
NSManagedObjectModel *sourceModel = [[NSManagedObjectModel alloc]
initWithContentsOfURL:modelURL];
NSManagedObjectModel *destinationModel = [self managedObjectModel];
/*
To perform the migration, we also need a mapping model.
We have the source and destination model; NSMapping model provides
a convenience method to find the correct mapping model from a given
array of bundles.
*/
NSArray *bundles = [NSArray arrayWithObject:[NSBundle mainBundle]];
NSMappingModel *mappingModel = [NSMappingModel
mappingModelFromBundles:bundles forSourceModel:sourceModel
destinationModel:destinationModel];
if (mappingModel == nil)
{
// should create a suitable NSError and set in 'error'
return NO;
}
/*
Move the legacy file out of the way
*/
NSString *originalPath = [url path];
NSString *legacyPath = [NSString stringWithFormat:@"%@~",
originalPath];
BOOL success = [[NSFileManager defaultManager] movePath:originalPath
toPath:legacyPath handler:nil];
if (!success) {
return NO;
}
NSURL *sourceURL = [NSURL fileURLWithPath:legacyPath isDirectory:NO];
NSURL *destinationURL = [NSURL fileURLWithPath:originalPath
isDirectory:NO];
/*
Create the migration manager and perform the migration
*/
NSMigrationManager *migrationManager = [[NSMigrationManager alloc]
initWithSourceModel:sourceModel destinationModel:destinationModel];
ok = [migrationManager migrateStoreFromURL:sourceURL
type:NSSQLiteStoreType options:storeOptions
withMappingModel:mappingModel toDestinationURL:destinationURL
destinationType:NSSQLiteStoreType destinationOptions:storeOptions
error:error];
[migrationManager release];
if (!ok)
{
return NO;
}
/*
Add the new store to the store coordinator and set the file URL
*/
NSPersistentStoreCoordinator *psc = [[self managedObjectContext]
persistentStoreCoordinator];
NSPersistentStore *destinationStore = [psc
addPersistentStoreWithType:NSSQLiteStoreType
configuration:configuration URL:destinationURL options:storeOptions
error:error];
if (destinationStore == nil)
{
return NO;
}
[self setFileURL:destinationURL];
}
Best,
Pierre
On Nov 6, 2007, at 8:50 PM, Adam Swift wrote:
>
> On Nov 6, 2007, at 7:05 AM, Pierre Bernard wrote:
>
>> Hi!
>>
>> I am seeing problems with Core Data automatic migration reading
>> files created using Tiger.
>>
>> The problem is triggered by the fact that Core Data determines the
>> source model to use by looking at the file's metadata. Legacy files
>> my lack the required NSStoreModelVersionHashes value. Unfortunately
>> Core Data currently (9A581) does not try to derive that value from
>> the file's actual content. It just fails to read the file.
>>
>> My workaround is to let Core Data have a pass at the file. If it
>> fails, I check for the missing NSStoreModelVersionHashes value. If
>> it is indeed missing, I load appropriate metadata from a PLIST file
>> and amend the source file.
>>
>> Another solution would be to manually instantiate a migration
>> manager with the 1.0 model for source model. In the end I decided
>> against this solution which involves more code. The below solution
>> will work gracefully once the Core Data bug is fixed. I.e. the
>> workaround will never again be called.
>
> There's no way for Core Data to reliably determine the appropriate
> model for a Tiger store, consider that a store may have been created
> by an a run-time data model that was constructed from any number of
> entities from any number of models (or constructed programmatically
> entirely in-memory).
>
> When version hashes are not available, your best bet is to create a
> migration manager with the appropriate inputs.
>
> - adam
>
>> Best,
>> Pierre Bernard
>> Houdah Software s.à r.l.
>>
>> - (BOOL)configurePersistentStoreCoordinatorForURL:(NSURL *)url
>> ofType:(NSString *)fileType
>> modelConfiguration:(NSString *)configuration
>> storeOptions:(NSDictionary *)storeOptions
>> error:(NSError **)error
>> {
>> NSMutableDictionary *newStoreOptions;
>>
>> if (storeOptions == nil)
>> {
>> newStoreOptions = [NSMutableDictionary dictionary];
>> }
>> else
>> {
>> newStoreOptions = [[storeOptions mutableCopy] autorelease];
>> }
>>
>> [newStoreOptions setObject:[NSNumber numberWithBool:YES]
>> forKey:NSMigratePersistentStoresAutomaticallyOption];
>>
>> BOOL ok = [super configurePersistentStoreCoordinatorForURL:url
>> ofType:fileType
>> modelConfiguration:configuration
>> storeOptions:newStoreOptions
>> error:error];
>>
>> if (!ok) {
>> /*
>> Legacy files created under Tiger may lack necessary metadata.
>> Add the metadata matching 1.0 files and retry.
>> */
>> NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator
>> metadataForPersistentStoreOfType:NSSQLiteStoreType URL:url
>> error:error];
>> id versionHashes = [sourceMetadata
>> objectForKey:@"NSStoreModelVersionHashes"];
>>
>> if (versionHashes == nil) {
>> NSString *legacyMetadataPath = [[NSBundle mainBundle]
>> pathForResource:@"LegacyMetadata" ofType:@"plist"];
>> NSMutableDictionary *metadata = [NSMutableDictionary
>> dictionaryWithContentsOfFile:legacyMetadataPath];
>>
>> [metadata addEntriesFromDictionary:sourceMetadata];
>>
>> if (![NSPersistentStoreCoordinator setMetadata:metadata
>> forPersistentStoreOfType:NSSQLiteStoreType URL:url error:error]) {
>> return NO;
>> }
>>
>> *error = nil;
>> ok = [super configurePersistentStoreCoordinatorForURL:url
>> ofType:fileType
>> modelConfiguration:configuration
>> storeOptions:newStoreOptions
>> error:error];
>> }
>> }
>>
>> if (ok)
>> {
>> /*
>> If all went well, update the metadata
>> */
>>
>> NSURL *fileURL = [self fileURL];
>>
>> if (fileURL == nil) {
>> // File URL is null when writing new files
>> fileURL = url;
>> }
>>
>> NSPersistentStoreCoordinator *psc = [[self managedObjectContext]
>> persistentStoreCoordinator];
>>
>> id pStore = [psc persistentStoreForURL:fileURL];
>>
>> /*
>> configurePersistentStoreCoordinatorForURL is called when
>> document reopened
>> Check for existing metadata to avoid overwriting unnecessarily
>> */
>> id existingMetadata = [[psc metadataForPersistentStore:pStore]
>> objectForKey:(NSString *)kMDItemKeywords];
>>
>> if (existingMetadata == nil)
>> {
>> if (![self setMetadataForStoreAtURL:fileURL])
>> {
>> return NO;
>> }
>> }
>> }
>>
>> return ok;
>> }
>>
>> ---
>> Pierre Bernard
>> http://www.bernard-web.com/pierre
>> http://www.houdah.com
>>
>>
>>
>> _______________________________________________
>>
>> Cocoa-dev mailing list (<email_removed>)
>>
>> Please do not post admin requests or moderator comments to the list.
>> Contact the moderators at cocoa-dev-admins(at)lists.apple.com
>>
>> Help/Unsubscribe/Update your Subscription:
>> http://lists.apple.com/mailman/options/cocoa-dev/<email_removed>
>>
>> This email sent to <email_removed>
>
---
Pierre Bernard
http://www.bernard-web.com/pierre
http://www.houdah.com
DATE : Tue Nov 06 21:17:52 2007
Adam,
Thanks for clarifying this. I can find no word about this in the
documentation. This is a very serious limitation and should be
mentioned.
Is there really no way to infer entity hashes from the tables
available in the SQLite store at hand?
Wouldn't it be great if one could specify a default legacy model to
use on Tiger files?
Would you consider the below code to be preferable to the workaround I
posted earlier?
NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator
metadataForPersistentStoreOfType:NSSQLiteStoreType URL:url error:error];
if (sourceMetadata == nil)
{
return NO;
}
id versionHashes = [sourceMetadata
objectForKey:@"NSStoreModelVersionHashes"];
BOOL ok = NO;
if (versionHashes != nil) {
NSMutableDictionary *newStoreOptions;
if (storeOptions == nil)
{
newStoreOptions = [NSMutableDictionary dictionary];
}
else
{
newStoreOptions = [[storeOptions mutableCopy] autorelease];
}
[newStoreOptions setObject:[NSNumber numberWithBool:YES]
forKey:NSMigratePersistentStoresAutomaticallyOption];
ok = [super configurePersistentStoreCoordinatorForURL:url
ofType:fileType
modelConfiguration:configuration
storeOptions:newStoreOptions
error:error];
}
else {
NSURL *modelURL = [NSURL fileURLWithPath:[Document
pathForModelNamed:@"HoudahSpot"]];
NSManagedObjectModel *sourceModel = [[NSManagedObjectModel alloc]
initWithContentsOfURL:modelURL];
NSManagedObjectModel *destinationModel = [self managedObjectModel];
/*
To perform the migration, we also need a mapping model.
We have the source and destination model; NSMapping model provides
a convenience method to find the correct mapping model from a given
array of bundles.
*/
NSArray *bundles = [NSArray arrayWithObject:[NSBundle mainBundle]];
NSMappingModel *mappingModel = [NSMappingModel
mappingModelFromBundles:bundles forSourceModel:sourceModel
destinationModel:destinationModel];
if (mappingModel == nil)
{
// should create a suitable NSError and set in 'error'
return NO;
}
/*
Move the legacy file out of the way
*/
NSString *originalPath = [url path];
NSString *legacyPath = [NSString stringWithFormat:@"%@~",
originalPath];
BOOL success = [[NSFileManager defaultManager] movePath:originalPath
toPath:legacyPath handler:nil];
if (!success) {
return NO;
}
NSURL *sourceURL = [NSURL fileURLWithPath:legacyPath isDirectory:NO];
NSURL *destinationURL = [NSURL fileURLWithPath:originalPath
isDirectory:NO];
/*
Create the migration manager and perform the migration
*/
NSMigrationManager *migrationManager = [[NSMigrationManager alloc]
initWithSourceModel:sourceModel destinationModel:destinationModel];
ok = [migrationManager migrateStoreFromURL:sourceURL
type:NSSQLiteStoreType options:storeOptions
withMappingModel:mappingModel toDestinationURL:destinationURL
destinationType:NSSQLiteStoreType destinationOptions:storeOptions
error:error];
[migrationManager release];
if (!ok)
{
return NO;
}
/*
Add the new store to the store coordinator and set the file URL
*/
NSPersistentStoreCoordinator *psc = [[self managedObjectContext]
persistentStoreCoordinator];
NSPersistentStore *destinationStore = [psc
addPersistentStoreWithType:NSSQLiteStoreType
configuration:configuration URL:destinationURL options:storeOptions
error:error];
if (destinationStore == nil)
{
return NO;
}
[self setFileURL:destinationURL];
}
Best,
Pierre
On Nov 6, 2007, at 8:50 PM, Adam Swift wrote:
>
> On Nov 6, 2007, at 7:05 AM, Pierre Bernard wrote:
>
>> Hi!
>>
>> I am seeing problems with Core Data automatic migration reading
>> files created using Tiger.
>>
>> The problem is triggered by the fact that Core Data determines the
>> source model to use by looking at the file's metadata. Legacy files
>> my lack the required NSStoreModelVersionHashes value. Unfortunately
>> Core Data currently (9A581) does not try to derive that value from
>> the file's actual content. It just fails to read the file.
>>
>> My workaround is to let Core Data have a pass at the file. If it
>> fails, I check for the missing NSStoreModelVersionHashes value. If
>> it is indeed missing, I load appropriate metadata from a PLIST file
>> and amend the source file.
>>
>> Another solution would be to manually instantiate a migration
>> manager with the 1.0 model for source model. In the end I decided
>> against this solution which involves more code. The below solution
>> will work gracefully once the Core Data bug is fixed. I.e. the
>> workaround will never again be called.
>
> There's no way for Core Data to reliably determine the appropriate
> model for a Tiger store, consider that a store may have been created
> by an a run-time data model that was constructed from any number of
> entities from any number of models (or constructed programmatically
> entirely in-memory).
>
> When version hashes are not available, your best bet is to create a
> migration manager with the appropriate inputs.
>
> - adam
>
>> Best,
>> Pierre Bernard
>> Houdah Software s.à r.l.
>>
>> - (BOOL)configurePersistentStoreCoordinatorForURL:(NSURL *)url
>> ofType:(NSString *)fileType
>> modelConfiguration:(NSString *)configuration
>> storeOptions:(NSDictionary *)storeOptions
>> error:(NSError **)error
>> {
>> NSMutableDictionary *newStoreOptions;
>>
>> if (storeOptions == nil)
>> {
>> newStoreOptions = [NSMutableDictionary dictionary];
>> }
>> else
>> {
>> newStoreOptions = [[storeOptions mutableCopy] autorelease];
>> }
>>
>> [newStoreOptions setObject:[NSNumber numberWithBool:YES]
>> forKey:NSMigratePersistentStoresAutomaticallyOption];
>>
>> BOOL ok = [super configurePersistentStoreCoordinatorForURL:url
>> ofType:fileType
>> modelConfiguration:configuration
>> storeOptions:newStoreOptions
>> error:error];
>>
>> if (!ok) {
>> /*
>> Legacy files created under Tiger may lack necessary metadata.
>> Add the metadata matching 1.0 files and retry.
>> */
>> NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator
>> metadataForPersistentStoreOfType:NSSQLiteStoreType URL:url
>> error:error];
>> id versionHashes = [sourceMetadata
>> objectForKey:@"NSStoreModelVersionHashes"];
>>
>> if (versionHashes == nil) {
>> NSString *legacyMetadataPath = [[NSBundle mainBundle]
>> pathForResource:@"LegacyMetadata" ofType:@"plist"];
>> NSMutableDictionary *metadata = [NSMutableDictionary
>> dictionaryWithContentsOfFile:legacyMetadataPath];
>>
>> [metadata addEntriesFromDictionary:sourceMetadata];
>>
>> if (![NSPersistentStoreCoordinator setMetadata:metadata
>> forPersistentStoreOfType:NSSQLiteStoreType URL:url error:error]) {
>> return NO;
>> }
>>
>> *error = nil;
>> ok = [super configurePersistentStoreCoordinatorForURL:url
>> ofType:fileType
>> modelConfiguration:configuration
>> storeOptions:newStoreOptions
>> error:error];
>> }
>> }
>>
>> if (ok)
>> {
>> /*
>> If all went well, update the metadata
>> */
>>
>> NSURL *fileURL = [self fileURL];
>>
>> if (fileURL == nil) {
>> // File URL is null when writing new files
>> fileURL = url;
>> }
>>
>> NSPersistentStoreCoordinator *psc = [[self managedObjectContext]
>> persistentStoreCoordinator];
>>
>> id pStore = [psc persistentStoreForURL:fileURL];
>>
>> /*
>> configurePersistentStoreCoordinatorForURL is called when
>> document reopened
>> Check for existing metadata to avoid overwriting unnecessarily
>> */
>> id existingMetadata = [[psc metadataForPersistentStore:pStore]
>> objectForKey:(NSString *)kMDItemKeywords];
>>
>> if (existingMetadata == nil)
>> {
>> if (![self setMetadataForStoreAtURL:fileURL])
>> {
>> return NO;
>> }
>> }
>> }
>>
>> return ok;
>> }
>>
>> ---
>> Pierre Bernard
>> http://www.bernard-web.com/pierre
>> http://www.houdah.com
>>
>>
>>
>> _______________________________________________
>>
>> Cocoa-dev mailing list (<email_removed>)
>>
>> Please do not post admin requests or moderator comments to the list.
>> Contact the moderators at cocoa-dev-admins(at)lists.apple.com
>>
>> Help/Unsubscribe/Update your Subscription:
>> http://lists.apple.com/mailman/options/cocoa-dev/<email_removed>
>>
>> This email sent to <email_removed>
>
---
Pierre Bernard
http://www.bernard-web.com/pierre
http://www.houdah.com
| Related mails | Author | Date |
|---|---|---|
| Pierre Bernard | Nov 6, 16:05 | |
| Adam Swift | Nov 6, 20:50 | |
| Pierre Bernard | Nov 6, 21:17 | |
| Adam Swift | Nov 7, 00:09 |






Cocoa mail archive

