FROM : Adam Swift
DATE : Wed Nov 07 00:09:39 2007
On Nov 6, 2007, at 12:17 PM, Pierre Bernard wrote:
> 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.
I think that's a fair point, please file a documentation enhancement
request.
> Is there really no way to infer entity hashes from the tables
> available in the SQLite store at hand?
Unfortunately, no.
> Wouldn't it be great if one could specify a default legacy model to
> use on Tiger files?
Hm, maybe, it couldn't hurt to ask ;)
>
> Would you consider the below code to be preferable to the workaround
> I posted earlier?
Sure, seems like the right way to go. If there was a custom version
number (or other custom key/value pair) assigned in your Tiger data
store metadata you could verify that you're trying to open a
recognized version of the store file, and from the nit-picky
department, it'd be nice to revert the original file to it's original
name (no tilde) if migration fails.
>
>
> 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 : Wed Nov 07 00:09:39 2007
On Nov 6, 2007, at 12:17 PM, Pierre Bernard wrote:
> 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.
I think that's a fair point, please file a documentation enhancement
request.
> Is there really no way to infer entity hashes from the tables
> available in the SQLite store at hand?
Unfortunately, no.
> Wouldn't it be great if one could specify a default legacy model to
> use on Tiger files?
Hm, maybe, it couldn't hurt to ask ;)
>
> Would you consider the below code to be preferable to the workaround
> I posted earlier?
Sure, seems like the right way to go. If there was a custom version
number (or other custom key/value pair) assigned in your Tiger data
store metadata you could verify that you're trying to open a
recognized version of the store file, and from the nit-picky
department, it'd be nice to revert the original file to it's original
name (no tilde) if migration fails.
>
>
> 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

