Cocoa:CoreData - ManagedObjectContext中的多个实体

时间:2010-02-11 12:44:33

标签: cocoa core-data

我有两个实体,我也建模为类和核心数据模型实体/类看起来如下:

类:StateManager

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h> 
#import "StateManager.h"
#import "Constants.h"


@implementation StateManager 

@synthesize deviceID, physicalID, applicationName, applicationVersion;
@synthesize userName, userPassword, server, port, client, language, protocol;

-(bool)checkCompleteness{
if (physicalID == nil) {
    return false;
}
if (applicationName == nil) {
    return false;
}
if (applicationVersion == nil) {
    return false;
}
if (userName == nil) {
    return false;
}
if (userPassword == nil) {
    return false;
}
if (port == nil) {
    return false;
}
if (server == nil) {
    return false;
}
return true;
}
-(void)preserveState:(NSManagedObjectContext *)managedObjectContext{
// Step 1: Create Object
StateManager *inMemoryState = (StateManager *)[NSEntityDescription
                                     insertNewObjectForEntityForName:ENTITY_STATE
                                     inManagedObjectContext:managedObjectContext];
// Step 2: Set Properties
[inMemoryState setDeviceID:self.deviceID];
[inMemoryState setPhysicalID:self.physicalID];
[inMemoryState setApplicationName:self.applicationName];
[inMemoryState setApplicationVersion:self.applicationVersion];
//[inMemoryState setAutoRegister:[self getAutoRegister]];
[inMemoryState setUserName:self.userName];
[inMemoryState setUserPassword:self.userPassword];
[inMemoryState setServer:self.server];
[inMemoryState setPort:self.port];
[inMemoryState setClient:self.client];
[inMemoryState setLanguage:self.language];
[inMemoryState setProtocol:self.protocol];

// Step 3: Save Object
NSError *error;
if (![managedObjectContext save:&error]) {
     NSLog(@"Unresolved Core Data Save error %@, %@", error, [error userInfo]);
     exit(-1);
 }

}


-(StateManager *)loadState:(NSManagedObjectContext *)managedObjectContext{

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

NSEntityDescription *entityState = [NSEntityDescription entityForName:ENTITY_STATE 
                                               inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entityState];

NSError *error;

NSArray *items = [managedObjectContext
                  executeFetchRequest:fetchRequest error:&error];

if ([items count] > 0) {
    StateManager *inDatabaseState = (StateManager *)[items objectAtIndex:0];

    deviceID = [inDatabaseState valueForKey:@"deviceID"];
    physicalID = [inDatabaseState valueForKey:@"physicalID"];
    applicationName = [inDatabaseState valueForKey:@"applicationName"];
    applicationVersion = [inDatabaseState valueForKey:@"applicationVersion"];
    //autoRegister = [inDatabaseState valueForKey:@"autoRegister"];
    userName = [inDatabaseState valueForKey:@"userName"];
    userPassword = [inDatabaseState valueForKey:@"userPassword"];
    server = [inDatabaseState valueForKey:@"server"];
    port = [inDatabaseState valueForKey:@"port"];
    client = [inDatabaseState valueForKey:@"client"];
    language = [inDatabaseState valueForKey:@"language"];
    protocol = [inDatabaseState valueForKey:@"protocol"];

    [inDatabaseState release];
}

[fetchRequest release];
[entityState release]; 
[items release]; 
/*
 deviceID = @"1234";
 physicalID = @"12312";
 applicationName = @"erwerw";
 applicationVersion = @"applicationVersion";
 //autoRegister = [inDatabaseState valueForKey:@"autoRegister"];
 userName = @"userName";
 userPassword = @"userPassword";
 server = @"server";
 port = @"port";
 client = @"client";
 language = @"language";
 protocol = @"protocol";*/
 return self;

}

-(void)dealloc{

[deviceID release];
[physicalID release];
[applicationName release];
[applicationVersion release];
[userName release];
[userPassword release] ;
[server release];
[port release];
[client release];
[language release];
[protocol release];
[super dealloc];
}

@end

类:InboundQueueState

#import "InQueueState.h"


@implementation InQueueState 

@dynamic top;
@dynamic read;
@dynamic last;

@end

现在我正在尝试将这些对象数据从DB加载到我的应用程序中,如下所示:

  1. 如果查看类StateManager,您将看到一个方法loadState,它尝试使用托管对象上下文读取实体“StateManager”。此上下文已从主类传递给此类。

  2. 下面“InboundQueue”类中显示的另一个方法“readQueue”尝试遵循使用全局托管对象上下文加载实体“InboundState”的相同范例,但失败并显示以下错误:

  3.   

    错误:[NSFetchRequest objectID]:发送到的无法识别的选择器   实例0x3a1a300由于未捕获的异常而终止应用程序   'NSInvalidArgumentException',原因:'*** - [NSFetchRequest objectID]:   无法识别的选择器发送到实例0x3a1a300'

    类别:InboundQueue

    #import "InboundQueue.h"
    #import <CoreData/CoreData.h> 
    #import "Constants.h"
    #import "InQueueItem.h"
    
    @implementation InboundQueue
    
    -(int)last{
    return [queueState last];
    }
    
    -(int)top{
    return [queueState top];
    }
    
    -(int)read{
    return [queueState read];
    }
    
    -(InboundQueue *)initInboundQueue:(NSManagedObjectContext *)managedObjectContext{
    
    //load the inbound queue counters and initialize the inbound queue object with the values
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    
    NSEntityDescription *entityState = [NSEntityDescription entityForName:INQUEUE_STATE 
                                                   inManagedObjectContext:managedObjectContext];
    [fetchRequest setEntity:entityState];
    
    NSError *error;
    NSArray *msgs = [managedObjectContext
                      executeFetchRequest:fetchRequest error:&error];
    
    if ([msgs count] > 0) {
        queueState = [msgs objectAtIndex:0]; //contains the values of the counters related to inbound queue at any point in time
    }
    
    [fetchRequest, entityState, msgs release];
    return self;
    }
    
    -(NSMutableArray *)readQueue:(NSManagedObjectContext*) managedObjectContext{
    //load the inbound queue counters and initialize the inbound queue object with the values
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    
    NSEntityDescription *entityState = [NSEntityDescription entityForName:INQUEUE 
                                                   inManagedObjectContext:managedObjectContext];
    [fetchRequest setEntity:entityState];
    
    NSError *error;
    NSArray *queueContent = [managedObjectContext
                      executeFetchRequest:fetchRequest error:&error];
    [queueData setArray:queueContent];
    
    [fetchRequest, entityState, error release];
    return queueData;
    }
    
    -(void)confirm:(int)msgID managedObjectContext:(NSManagedObjectContext*) managedObjectContext{
    if (msgID < [queueState top]) {
        return;
    }
    if (msgID > [queueState last]) {
        return;
    }
    //remove items from queue which are lower than the confrmed message ID
    for (InQueueItem *item in queueData) {
        int currentMsgId = [item MSG_ID]; 
        if ( currentMsgId <= msgID) {
            //delete the item from queue and adjust counters
    
            [queueData removeObject:item];
        }
    }
    [queueState setTop:(msgID + 1)];
    if ([queueState read] < [queueState top]) {
        [queueState setRead:[queueState top]]; //realign the top counter
    }
    //persist the changes from context to database
    NSError *error;
    if (![managedObjectContext save:&error]) {
        NSLog(@"Unresolved Core Data Save error %@, %@", error, [error userInfo]);
        exit(-1);
    }
    }
    
    -(void)add:(InQueueItem *)item  managedObjectContext:(NSManagedObjectContext*) managedObjectContext{
    //validate the message id
    if (([queueState last] > ([item MSG_ID] - 1))) {
        //ignore this message since we have already received a message with this message id     
    }else if (([queueState last] < ([item MSG_ID] - 1))) {
        //raise an invalid message ID exception => data loss    
    }else {
        if ([queueState last] == 0) {
            //need to initialize counters as this is the first entry
            [queueState setTop:[item MSG_ID]];
            [queueState setLast:[item MSG_ID]];
    
        }else {
            //increment last
            [queueState setLast:([queueState last] + 1)];
        }
        //now insert the item into queue
        [queueData addObject:item];
    }
    //persist the changes from context to database
    NSError *error;
    if (![managedObjectContext save:&error]) {
        NSLog(@"Unresolved Core Data Save error %@, %@", error, [error userInfo]);
        exit(-1);
    }
    
    }
    
    -(void)dealloc{
    [queueData release];
    [queueState  release];
    [super dealloc];
    }
    @end
    

    我的理解是,相同的托管对象上下文可以加载数据模型的所有对象并允许操作,但我不确定为什么在我的情况下它只适用于一个对象。

1 个答案:

答案 0 :(得分:4)

每个实体不需要单独的ManagedObjectContext。无论模型包含多少实体,ManagedObjectContext都会控制整个模型的整个对象图。 (您可以创建多个上下文但不能处理多个实体。)

如果你的A fetch正在踩到你B提取,那么你很可能没有正确配置你的B提取。你是否试图重复使用你为A创建的获取?

Fetches非常独特。每个提取都是单独配置的,您不应该将它们重用于其他实体或更改其提取参数(尽管该类不强制执行此操作。)

您应该初始化B的完全独立的抓取。

Edit01:

根据您发布的代码和错误的详细信息,我认为问题很可能是您没有为InQueueState课程返回正确的实体说明。

我建议记录返回的实体:

NSEntityDescription *entityState = [NSEntityDescription entityForName:INQUEUE 
                                               inManagedObjectContext:managedObjectContext]

确保它不是零。

您(作为标准练习)还需要在使用之前检查NSArray *queueContent是否为空或空。

Edit02:

此外,这一行:

[fetchRequest, entityState, error release];

您不需要释放entityState也不需要发生错误,因为您不会初始化或创建任何一个,而只是保留对从其他对象返回的引用。