可以使用两个单独的 SQLite 数据库吗?

Posted

技术标签:

【中文标题】可以使用两个单独的 SQLite 数据库吗?【英文标题】:Possible to use two separate SQLite databases? 【发布时间】:2010-10-16 01:37:26 【问题描述】:

我有一个 sqlite 数据库,其中存储了用户定义的信息和对用户只读的信息。感觉以后可能需要修改只读信息,不想做一个整体的数据迁移。有没有一种方法可以让我使用一个可以轻松替换的单独的 sqlite 数据库来获取只读信息?如果是这样,您能否就如何做到这一点给出一些指导?我很困惑,因为我目前在 xcdatamodel 上拥有所有实体 - 我会创建两个数据模型吗?不知道这将如何工作。提前致谢。


这不起作用,但请随时提供反馈。

- (NSManagedObjectModel *)managedObjectModel 

    NSLog(@"%s", __FUNCTION__);
    if (managedObjectModel != nil) 
        return managedObjectModel;
    
    //managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];

    NSString *mainPath = [[NSBundle mainBundle] pathForResource:@"MyApp" ofType:@"mom"];
    NSURL *mainMomURL = [NSURL fileURLWithPath:mainPath];
    managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:mainMomURL];

    [managedObjectModel setEntities:[NSArray arrayWithObjects:
                                          [[managedObjectModel entitiesByName] objectForKey:@"Version"],
                                          [[managedObjectModel entitiesByName] objectForKey:@"Book"],
                                          nil] forConfiguration:@"info"];

    [managedObjectModel setEntities:[NSArray arrayWithObjects:
                                          [[managedObjectModel entitiesByName] objectForKey:@"Settings"],
                                          [[managedObjectModel entitiesByName] objectForKey:@"Persons"],
                                          nil] forConfiguration:@"main"];

    return managedObjectModel;

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator 

    NSLog(@"%s", __FUNCTION__);
    if (persistentStoreCoordinator != nil) 
        return persistentStoreCoordinator;
    

    NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"Main.sqlite"];

    NSFileManager *fileManager = [NSFileManager defaultManager];
    if (![fileManager fileExistsAtPath:storePath]) 
        NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:@"Default" ofType:@"sqlite"];
        if (defaultStorePath) 
            [fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
        
    

    NSURL *storeUrl = [NSURL fileURLWithPath:storePath];
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];    


    NSString *infoStorePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"Info.sqlite"];
    if (![fileManager fileExistsAtPath:infoStorePath]) 
        NSString *defaultInfoStorePath = [[NSBundle mainBundle] pathForResource:@"DefaultInfo" ofType:@"sqlite"];
        if (defaultInfoStorePath) 
            [fileManager copyItemAtPath:defaultInfoStorePath toPath:infoStorePath error:NULL];
        
    

    NSURL *infoStoreUrl = [NSURL fileURLWithPath:infoStorePath];

    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
    //persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] init]; 

    NSPersistentStore *mainStore = [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:@"main" URL:storeUrl options:options error:&error];
    NSPersistentStore *infoStore = [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:@"verses" URL:infoStoreUrl options:options error:&error];

    NSManagedObject *settingsEntity = [[NSManagedObject alloc] initWithEntity:[[managedObjectModel entitiesByName] objectForKey:@"Settings"] insertIntoManagedObjectContext:self.managedObjectContext];
    [self.managedObjectContext assignObject:settingsEntity toPersistentStore:mainStore];

    NSManagedObject *persons = [[NSManagedObject alloc] initWithEntity:[[managedObjectModel entitiesByName] objectForKey:@"Persons"] insertIntoManagedObjectContext:self.managedObjectContext];
    [self.managedObjectContext persons toPersistentStore:mainStore];

NSManagedObject *version = [[NSManagedObject alloc] initWithEntity:[[managedObjectModel entitiesByName] objectForKey:@"Version"] insertIntoManagedObjectContext:self.managedObjectContext];
[self.managedObjectContext assignObject:version toPersistentStore:infoStore];

NSManagedObject *book = [[NSManagedObject alloc] initWithEntity:[[managedObjectModel entitiesByName] objectForKey:@"Book"] insertIntoManagedObjectContext:self.managedObjectContext];
[self.managedObjectContext assignObject:book toPersistentStore:infoStore];

- (NSManagedObjectContext *)managedObjectContext 

    NSLog(@"%s", __FUNCTION__);
    if (managedObjectContext != nil) 
        return managedObjectContext;
    

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) 
        managedObjectContext = [NSManagedObjectContext new];
        [managedObjectContext setPersistentStoreCoordinator: coordinator];
    
    return managedObjectContext;

【问题讨论】:

显然可以有多个持久存储,每个存储都有不同的实体“配置”,所有这些都由同一个 NSPersistentStoreCoordinator 管理,但我不知道如何设置它。希望有人会过来分享一个例子,因为我也有兴趣。 【参考方案1】:

来自文档的部分回答:

http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/CoreData/Articles/cdMOM.html

配置

一个配置有一个名字和一个 关联的实体集。套装 可能重叠——即一个给定的实体 可能出现在多个 配置。你建立 以编程方式使用配置 setEntities:forConfiguration: 或使用 Xcode 数据建模工具(参见 Xcode 核心数据工具),以及 检索给定的实体 配置名称使用 实体配置:。

您通常使用配置,如果 你想存储不同的实体 在不同的商店。一个执着 商店协调员只能有一个 托管对象模型,所以默认情况下 与给定关联的每个商店 coordinator 必须包含相同的 实体。要解决此问题 限制,您可以创建一个模型 包含所有的联合 您要使用的实体。然后是你 在模型中创建配置 每个实体的子集 你想用。然后你可以使用这个 创建协调器时的模型。 添加商店时,请指定 不同的店铺属性 配置。当你在创作 但是,您的配置请记住 你不能创建跨店 关系。

然后 NSPersistentStoreCoordinator 允许您创建多个商店,每个商店都有不同的配置。

任何人都有如何做到这一切的例子吗?

【讨论】:

谢谢尼姆罗德。很高兴知道它可以做到,现在要弄清楚如何做到这一点。到目前为止的搜索还没有给出任何例子,但我会继续寻找。谁先找到它可以在这里发布,或者希望有人举个例子。顺便说一句,新来的,我很欣赏你的回答,但我想在我们得到最终答案之前我不应该打勾——对吗?? 我同意。我也想看到一个完整的答案,所以请不要勾选这个。顺便说一句,请注意,不幸的是,它说您不能建立跨商店关系....猜猜这是出于参照完整性的原因。 另外,我发现的一些例子给出了一个例子:cimgf.com/2009/05/03/core-data-and-plug-ins 感谢您在这个 Nimrod 上坚持我。在这方面我还是个新手.. 初步浏览了该链接中的代码,它看起来有点过头了,但是当我有时间时,我会尝试更深入地研究。我认为 ImHuntingWabbits 是在正确的轨道上,希望我们能解决这个问题...... 我认为 setEntities forConfiguration 加上 ImHuntingWabbits 的代码是可行的方法,但我肯定可以使用完整的代码示例。我正在尝试,但我的头撞到了墙上!【参考方案2】:

您实际上可以使用单个数据模型来完成此操作,但是您需要手动(在代码中)将实体分配给不同的 NSPersistentStore 实例,一些代码:

NSPersistentStoreCoordinator *coord = [[NSPersistentStoreCoordinator alloc] init];
NSPersistentStore *userStore = [coord addPersistentStoreWithType:NSSQLiteStore configuration:nil URL:someFileURL options:someoptions error:&error];
NSPersistentStore *otherStore = [coord addPersistentStoreWithType:NSSQLiteStore configuration:nil URL:someFileURL2 options:someoptions error:&error];

//Now you use the two separate stores through a managed object context that references the coordinator
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init];
[context setPersistentStoreCoordinator:coord];

NSManagedObject *userObject = [[NSManagedObject alloc] initWithEntity:entityDescFromModel insertIntoManagedObjectContext:context];
[context assignObject:userObject toPersistentStore:userStore];

NSManagedObject *otherObject = [[NSManagedObject alloc] initWithEntity:entityDescFromModel insertIntoManagedObjectContext:context];
[context assignObject:otherObject toPersistentStore:otherStore];

通过这种方式,您始终可以指定将对象保存在哪个存储中。我认为一旦对象在各自的存储中,您就不必做任何额外的工作,即您应该能够执行在引用两个商店的协调器的上下文中获取规范。

【讨论】:

感谢您的建议。我尝试了这个并使用 PersistentStoreCoordinator 的 alloc init 撞墙,因为我在没有 initWithManagedObjectModel 的情况下使用它。如果我使用 initWithManagedObjectModel,它可以工作,但我必须使用合并的 managedObjectModel。这会生成两个 sqlite 文件,但每个文件中都有所有实体!如果没有 initWithManagedObjectModel,应用程序只会崩溃而没有错误信息。当然我错过了什么,但是什么? 我认为问题在于配置:nil 部分。从我读过的内容中,这需要指定分配给该持久存储的实体列表。 "configurationName 要使用的托管对象模型配置的名称。如果您不想指定配置,则传递 nil。" 好的,试试这个。打开你的模型。点击一个实体。点击右上角的小扳手图标。您应该会看到“配置”的内容。添加两个配置,每个商店一个,并选中该实体的一个框。与其他实体重复检查适当的配置。现在,将这些名称指定为上面“配置:”的字符串 好的,尼姆罗德。我尝试过这个。在这一点上,我只是在玩很多不同的方法,调整这个和调整那个。我可以让它生成两个 sqlite 文件。每个都有所有实体或每个没有实体。我会发布我的代码,但我已经更改了一百次,而且一团糟。我正在使用 - (NSPersistentStoreCoordinator *)persistentStoreCoordinator 方法,我还为我的每个数据模型创建了一个 managedObjectModel(我有两个,我知道可以用一个来完成,但我认为这不是问题)。我不知道我有什么问题——我通常可以得到这些东西! 无法获取。生成了两个文件,一个始终包含所有实体,一个始终完全为空。把叉子插在我身上。我受够了。继续下一期。【参考方案3】:

好吧,这就是我最终要做的。两个 managedObjectModels、两个 managedObjectContexts、两个 persistentStoreCoordinators,因此也就有了两个持久化存储。完全分开,这很好,因为两个存储中的数据之间根本没有关系。这就是为什么创建 sqlite 文件时没有实体和数据的原因:在创建实体之前,您需要在数据库中执行至少一个 fetch 请求。谁知道?好吧,显然,不是我。无论如何,这对我来说效果很好,因为在应用程序启动之前我什至不会准备好第二家商店(它是为了附加功能)。现在,当我的数据文件最终准备就绪时,我可以添加 sqlite 文件,取消注释与其相关的代码,然后将应用程序发送到应用商店。它不会触及包含用户数据的商店。而且,我将把我的只读存储保留在我的包中,这样就不会迁移了。听起来怎么样?

【讨论】:

嗨@SAHM,您的帖子已经过去了 5 年!你有没有找到更好的解决方案?我正在处理同样的问题,刚刚找到您的帖子:***.com/questions/33165653/… 嗨@DAN,我最终没有制作这个应用程序!很抱歉,我希望我能为您提供更好的信息。【参考方案4】:

好的,我发现了如何添加另一个数据模型。文件>新建文件>Iphone OS>资源>数据模型。将我的实体移至该数据模型。编译并似乎运行,但没有数据。问题是,仍然只有一个 sqlite 文件。需要找出如何使用两个,并将每个与适当的模型相关联。然后,应该能够在应用更新时覆盖新模型的默认 sqlite 文件。但是我认为我仍然需要进行迁移,因为它会根据我指定的默认文件在 iPhone 上创建一个 sqlite 文件。我希望这不应该是一个艰难的迁移,因为我不会在文件中包含任何用户数据。学习,但仍然,任何进一步的帮助表示赞赏。

【讨论】:

以上是关于可以使用两个单独的 SQLite 数据库吗?的主要内容,如果未能解决你的问题,请参考以下文章

您可以从位于单个结果集中的两个单独的表中提取数据吗? [不加入问题]

Python 操作 SQLite 数据库

有适合python使用的数据库连接池或代理吗

SQLCipher、encrypted-core-data 和 iOS - 两个 .sqlite 文件正常吗?

Sqlite 数据库实例线程安全吗

使用jooq上下文将内存sqlite转储到字节[]