如何将所有获取请求放入Core Data DAL?

时间:2010-07-13 13:36:40

标签: iphone objective-c core-data ipad

来自.net背景的Objective-C和Core Data的全新内容我真的想把我的所有获取请求放到某种我可以调用的类中,最好是静态地获取我的对象,例如: / p>

ObjectType * myObject = [CoreDataDAL GetObject:ID];

任何人都有实施此模式的模式吗?

我现在正在通过一个攻击,但它可能不太正确,我会在发布代码时发布代码。

EIDT: 这是我现在的代码 - 似乎工作得很好 - 如果我走错路,请把它撕掉 - 这是基本的DAL:

#import "CoreDataDAL.h"
#import "CoreDataAppDelegate.h"

@implementation CoreDataDAL

@synthesize managedObjectContext;

-(id)init {
    if (self=[super init]) {
        CoreDataAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
        self.managedObjectContext = appDelegate.managedObjectContext;
    }
    return self;
}

-(Client *) GetClient:(NSString *) ClientID{
    /* Client Fetch Request */
    NSFetchRequest *request = [[NSFetchRequest alloc]init];
    NSEntityDescription *entityType = [NSEntityDescription entityForName:@"Client" inManagedObjectContext:managedObjectContext];
    [request setEntity:entityType];
    NSPredicate *predicate =[NSPredicate predicateWithFormat:@"ClientID==%@",ClientID];
    [request setPredicate:predicate];

    NSError *error;
    NSArray *entities = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];

    return [entities objectAtIndex:0];
}

@end

以下是我在视图控制器中的使用方法:

CoreDataDAL *dal = [[CoreDataDAL alloc]init];
Client *client = [dal GetClient:clientID];
[dal release];

看起来很直接,想法?

2 个答案:

答案 0 :(得分:14)

不要这样做;你正在做的是将一个模式从一个上下文移植到另一个上下文中,它实际上没有意义。

首先,您不应该在Core Data中对ID进行建模;框架为您完成了NSManagedObjectID。因此,CoreDataDAL类上的-clientWithID:方法是多余的。 (请注意,我还更改了您的假设方法的名称,以遵循正确的Cocoa命名约定。)相反,您可以使用-[NSManagedObjectContext objectWithID:]-[NSManagedObjectContext existingObjectWithID:error:]来获取基于其NSManagedObjectID的对象。

同样,为您处理关系管理。您不需要在DAL中有一个方法可以(比方说)通过评估某个查询来获取应用于给定客户端的所有Address实例。您可以遍历客户端的多个addresses关系以获取它们,并直接操纵相同的关系(而不是设置外键等)。

最后,如果您确实希望有方法来执行专门的查询,您可以通过相应实体的fetched属性为其结果指定查询,也可以将该方法直接添加到相应的类中。 Objective-C中的类方法与C ++,Java或C#中的静态方法不同 - 它们可以像实例方法一样被覆盖,并且更适合这种用途。

例如,假设您的客户端实体具有syncID属性,表示它在某些Web服务中表示的对象的ID。 (请注意,这是专门用于将本地对象与远程对象相关联,而不是本地对象的“主键”。)您可能在与客户端实体关联的MyClient类上有类方法,如下所示:

@implementation MyClient

+ (NSString *)entityClassName
{
    return @"Client";
}

+ (NSEntityDescription *)entityInManagedObjectContext:(NSManagedObjectContext *)context
{
    return [NSEntityDescription entityForName:[self entityClassName] inManagedObjectContext:context];
}

+ (MyClient *)clientWithSyncID:(NSString *)syncID
        inManagedObjectContext:(NSManagedObjectContext *)context
                         error:(NSError **)error
{
    MyClient *result = nil;

    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:[self entityInManagedObjectContext:context]];
    [request setPredicate:[NSPredicate predicateWithFormat:@"syncID == %@", syncID]];
    [request setFetchLimit:1];

    NSArray *results = [context executeFetchRequest:request error:error];
    if ([results count] > 0) {
        result = [results objectAtIndex:0];
    } else {
        if (error != NULL) {
            *error = [NSError errorWithDomain:MyAppErrorDomain
                                         code:MyAppNoClientFoundError
                                     userInfo:nil];
        }
    }

    return result;
}

@end

这与您在DAL类中编写的内容类似,但它不是在一个位置合并所有提取,而是将提取的逻辑放在该类的特定托管对象类上,这实际上属于它所属的位置。由于Objective-C具有真正的类方法,您实际上可以将+entityInManagedObjectContext:+entityClassName等方法放在公共基类上,然后在子类中适当地仅覆盖后者(或甚至生成它)来自类名的适当实体名称。

总结一下:

  • 不要在对象ID,关系管理等方面重新创建Core Data已经为您实现的内容。
  • 利用类实例的多态性来保持代码清洁,而不是像“数据访问层”那样使用“实用程序”类。

答案 1 :(得分:1)

获取请求正确属于模型 - 视图 - 控制器模式中的各个控制器。获取将返回每个视图所需的特定顺序的特定信息。每个提取都是根据每个特定视图的需求而定制的。因此,将所有应用程序的提取放在单个对象中会破坏封装而不是增强它。只有获取的属性和获取的关系属于数据模型本身。

托管对象上下文在简单应用程序中执行数据对象的功能。它实现了将信息输入和输出Core Data堆栈所需的所有功能,例如- objectWithID:。大多数情况下,您需要做的就是将上下文传递给控制器​​,让它们配置对它的提取。

如果您的应用程序很大或具有多个上下文,您始终可以使用各种访问器和便捷方法将上下文包装在自定义管理器类中,以使Core Data操作更顺畅地运行。您可以合理安全地将管理器类实现为单例,以便在应用程序的任何位置轻松访问它。

编辑:

除了可变副本之外,代码看起来没问题。这是毫无意义的,会泄漏记忆。 entities数组仅需要一行,并且它是自动释放的。 Client对象保留由上下文管理。您应该测试错误并至少记录它以进行调试。

对于非访问者的方法名称,您确实要避免“获取”和“设置”。运行时查找以“get”和“set”开头的方法来查找访问器。按照惯例,所有方法名称都以小写字母开头。您可能希望使方法名称更具描述性,以便在您阅读它的几个月时自动注释。

所以:

[theCoreDataDal GetClient:vaugelyNamedString];

[theCoreDataDal clientWithClientID:vaugelyNamedString];

尝试将所有内容塞入一个对象时遇到的问题是,提取通常是唯一的,并根据特定接口的需要进行配置。 此外,您通常首先使用fetch来查找特定对象,然后在剩余的时间内根据输入未知行走关系,直到运行时。

核心数据是数据访问层。您为Core Data编写的大多数代码实际上都是控制器代码。这个GetClient方法在概念上没有任何问题,但是你多久会执行一次这种特定的提取?

当我创建一个Data Model Manager对象时,我主要用它来存储样板代码。例如,虽然每个获取请求都是唯一的,但它们都与实体描述相同,因此我自动生成方法以返回每个实体的基本提取并将其放入管理器中。然后我有另一个锅炉板方法来实际执行提取。在使用中,控制器向管理器询问特定实体的获取对象。控制器自定义提取,然后将其发送回管理器以执行提取并返回结果。

所有锅炉板都在经理中,所有定制的都在控制器中。