|
|
Sample Programs from NeXSTEP 3.3
/* RelationshipKeySetter.m created by cfeder on Tue 08-Nov-1994 */
#import "RelationshipKeySetter.h"
#import "ValueForKey.h"
#import <objc/objc-runtime.h>
@implementation EOEntity (attrsNamed)
- attributesNamed:(NSArray *)names
{
int i, count = [names count];
NSMutableArray *result = [NSMutableArray arrayWithCapacity:count];
for(i=0; i<count; i++) {
EOAttribute *attr = [self attributeNamed:[names objectAtIndex:i]];
if (attr)
[result addObject:attr];
}
return result;
}
- createObject
{
id eo = nil;
const char *className = [self className];
Class eoClass = objc_lookUpClass (className);
if (!eoClass) eoClass = [EOGenericRecord class];
if (eoClass) {
eo = [eoClass allocWithZone:[self zone]];
if ([eo respondsToSelector:@selector(initWithPrimaryKey:entity:)])
eo = [eo initWithPrimaryKey:nil entity:self];
else
[eo init];
}
return [eo autorelease];
}
@end
@implementation EORelationship (setPropsInDestObject)
- (NSArray *)sourceKeys
{
EORelationship *sourceRelationship = [self isFlattened]
? [[self componentRelationships] objectAtIndex:0] : self;
NSArray *joins = [sourceRelationship joins];
int i, count = [joins count];
NSMutableArray *results = [NSMutableArray arrayWithCapacity:count];
for (i = 0; i < count; i++) {
EOJoin *join = [joins objectAtIndex:i];
[results addObject:[[join sourceAttribute] name]];
}
return results;
}
- (void)setJoinPropertiesInDestinationObject:destination fromSourceObject:source
{
NSArray *joins = [self joins];
int i, count = [joins count];
for (i = 0; i < count; i++) {
EOJoin *join = [joins objectAtIndex:i];
id val = [(NSObject *)source valueForKey:[[join sourceAttribute] name]];
if (!val) val = [EONull null];
[destination takeValue:val forKey:[[join destinationAttribute] name]];
}
}
- (void)setJoinPropertiesInSourceObject:source fromDestinationObject:destination
{
NSArray *joins = [self joins];
int i, count = [joins count];
for (i = 0; i < count; i++) {
EOJoin *join = [joins objectAtIndex:i];
id val = [(NSObject*)destination valueForKey:[[join destinationAttribute] name]];
if (!val) val = [EONull null];
[source takeValue:val forKey:[[join sourceAttribute] name]];
}
}
- (NSDictionary *)destinationValuesFromSourceObject:sourceObject
{
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
[self setJoinPropertiesInDestinationObject:dictionary fromSourceObject:sourceObject];
return dictionary;
}
- (BOOL)hasJoinsOnPrimaryKeyOfSourceEntity
{
// FIX ME!
// this is not quite right for multi-attribute keys (the ordering may
// cause a false mismatch)
return [[self sourceKeys] isEqual:[[self entity] primaryKeyAttributeNames]];
}
- (void)updateMasterObject:master withNewDestinationObject:destination
// For to-one relationships!
{
// Decide which way to propagate the attributes based on which side of the
// relationship hooks to a primary key.
if ([self hasJoinsOnPrimaryKeyOfSourceEntity])
[self setJoinPropertiesInDestinationObject:destination fromSourceObject:master];
else
[self setJoinPropertiesInSourceObject:destination fromDestinationObject:master];
}
- linkObjectForSourceObject:master destinationObject:destination
// created an intermediate object for many-to-many relationship through
// an intermediate table. Initializes keys of intermediate object using
// keys from source and destination object
{
NSArray *relationships = [self componentRelationships];
EORelationship *sourceToLink = [relationships objectAtIndex:0];
EORelationship *linkToDestination = [relationships objectAtIndex:1];
EOEntity *linkEntity = [sourceToLink destinationEntity];
id link = [linkEntity createObject];
[sourceToLink setJoinPropertiesInDestinationObject:link fromSourceObject:master];
[linkToDestination setJoinPropertiesInSourceObject:link fromDestinationObject:destination];
return link;
}
- updateKeysForSourceObject:source destinationObject:destination
// Sets keys on source or destination to maintain consistency for
// the source to now map to destination for this relationship.
// Does not actually assign destination to ivar in source (just messes
// with the keys).
// Returns the modified object (source or destination). In the case of
// a many to many returns a newly created link object.
// The caller is reposible for inserting or updating the returned
// object in the database.
{
id modifiedObject = nil;
if ([self isToMany]) {
// figure out what values we need to snarf from our parents
if ([self isFlattened]) {
// Many to many create link obj Delete link none to-many
// I'm assuming there's only one link object...
modifiedObject = [self linkObjectForSourceObject:source destinationObject:destination];
} else {
// PK -> FK D->FK := M->PK none none to-many
[self setJoinPropertiesInDestinationObject:destination fromSourceObject:source];
modifiedObject = destination;
}
} else {
if ([self hasJoinsOnPrimaryKeyOfSourceEntity]) {
// PK -> PK D->PK := M->PK None none to-one
[self setJoinPropertiesInDestinationObject:destination fromSourceObject:source];
modifiedObject = destination;
} else {
// FK -> PK M->FK := D->PK M->FK=NULL none to-one
// We need to update the master with a new foreign key.
// send it to the dataSource as well...
[self setJoinPropertiesInSourceObject:source fromDestinationObject:destination];
modifiedObject = source;
}
}
return modifiedObject;
}
- updateKeysForDeleteOfDestinationObject:destination fromSourceObject:source
// Sets keys on source or destination to maintain consistency for
// a delete of the destination from the source. Returns the object
// modified, or a synthesized link object that must be deleted to
// affect the delete. The caller is responsible for updating the
// source object, or deleting the destination or link in the database.
//
// This does not actually update destination to ivar in source (just messes
// with the keys).
{
id modifiedObject = nil;
if ([self isToMany]) {
// figure out what values we need to snarf from our parents
if ([self isFlattened]) {
// Many to many create link obj Delete link to-many
// I'm assuming there's only one link object...
modifiedObject = [self linkObjectForSourceObject:source destinationObject:destination];
} else {
// PK -> FK D->FK := M->PK Delete D to-many
// Nil out foreign key in destination
[self setJoinPropertiesInDestinationObject:destination fromSourceObject:nil];
modifiedObject = destination;
}
} else {
if ([self hasJoinsOnPrimaryKeyOfSourceEntity]) {
// PK -> PK D->PK := M->PK delete D to-one
// no use nilling out destinations primary key. Row must be deleted
modifiedObject = destination;
} else {
// FK -> PK M->FK := D->PK M->FK=NULL to-one
// nil out foreign key in source
[self setJoinPropertiesInSourceObject:source fromDestinationObject:nil];
modifiedObject = source;
}
}
return modifiedObject;
}
@end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.