GNUstep Core Data  0.1
NSEntityDescription.m
1 /* Implementation of the NSEntityDescription class for the GNUstep
2  Core Data framework.
3  Copyright (C) 2005 Free Software Foundation, Inc.
4 
5  Written by: Saso Kiselkov <diablos@manga.sk>
6  Date: August 2005
7 
8  This file is part of the GNUstep Core Data framework.
9 
10  This library is free software; you can redistribute it and/or
11  modify it under the terms of the GNU Lesser General Public
12  License as published by the Free Software Foundation; either
13  version 2.1 of the License, or (at your option) any later version.
14 
15  This library is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public
21  License along with this library; if not, write to the Free
22  Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA.
23  */
24 
25 #import "CoreDataHeaders.h"
26 
27 // Ensures the entity can be edited. Raises an NSGenericException
28 // if the passed model is not nil and is not editable, with a reason
29 // set to `reason'.
30 static inline void EnsureEntityEditable(NSManagedObjectModel * model,
31  NSString * reason)
32 {
33  if (model != nil && [model _isEditable] == NO)
34  {
35  [NSException raise: NSGenericException format: reason];
36  }
37 }
38 
39 
40 @implementation NSEntityDescription
41 
42 
43 - (NSDictionary *) _filteredPropertiesOfClass: (Class) aClass
44 {
45  NSMutableDictionary * dict;
46  NSEnumerator * e;
47  NSPropertyDescription * property;
48 
49  dict = [NSMutableDictionary dictionaryWithCapacity: [_properties count]];
50  e = [_properties objectEnumerator];
51  while ((property = [e nextObject]) != nil)
52  {
53  if (aClass == Nil || [property isKindOfClass: aClass])
54  {
55  [dict setObject: property forKey: [property name]];
56  }
57  }
58 
59  return [[dict copy] autorelease];
60 }
61 
62 - (NSDictionary *) _fetchedPropertiesByName
63 {
64  return [self _filteredPropertiesOfClass: [NSFetchedPropertyDescription
65  class]];
66 }
67 
68 + (NSEntityDescription *) entityForName: (NSString *) entityName
69  inManagedObjectContext: (NSManagedObjectContext *) ctxt
70 {
71  return [[[[ctxt persistentStoreCoordinator] managedObjectModel]
72  entitiesByName] objectForKey: entityName];
73 }
74 
75 + (id) insertNewObjectForEntityForName: (NSString *) anEntityName
76  inManagedObjectContext: (NSManagedObjectContext *) aContext
77 {
78  NSEntityDescription * entity;
79  Class entityClass;
80  NSManagedObjectModel * model;
81 
82  model = [[aContext persistentStoreCoordinator] managedObjectModel];
83  entity = [[model entitiesByName] objectForKey: anEntityName];
84 
85  entityClass = NSClassFromString([entity managedObjectClassName]);
86 
87  return [[[entityClass alloc]
88  initWithEntity: entity insertIntoManagedObjectContext: aContext]
89  autorelease];
90 }
91 
92 - (void) dealloc
93 {
94  TEST_RELEASE(_name);
95 
96  // let go of our properties
97  [_properties makeObjectsPerformSelector: @selector(_setEntity:)
98  withObject: nil];
99  TEST_RELEASE(_properties);
100 
101  TEST_RELEASE(_userInfo);
102  TEST_RELEASE(_managedObjectClassName);
103 
104  [_subentities makeObjectsPerformSelector: @selector(setSuperentity:)
105  withObject: nil];
106 
107  TEST_RELEASE(_subentities);
108 
109  [super dealloc];
110 }
111 
112 
113 
114 - (NSString *) name
115 {
116  return _name;
117 }
118 
119 - (void) setName: (NSString *) aName
120 {
121  EnsureEntityEditable(_model, _(@"Tried to set the name of an "
122  @"entity alredy in use."));
123  ASSIGN(_name, aName);
124 }
125 
126 
127 
128 - (NSManagedObjectModel *) managedObjectModel
129 {
130  return _model;
131 }
132 
133 
134 
135 - (NSString *) managedObjectClassName
136 {
137  return _managedObjectClassName;
138 }
139 
140 - (void) setManagedObjectClassName: (NSString *) aName
141 {
142  EnsureEntityEditable(_model, _(@"Tried to set the managed object "
143  @"class name of an entity already in use"));
144  ASSIGN(_managedObjectClassName, aName);
145 }
146 
147 
148 
149 - (BOOL) isAbstract
150 {
151  return _abstract;
152 }
153 
154 - (void) setAbstract: (BOOL) flag
155 {
156  EnsureEntityEditable(_model, _(@"Tried to set abstractness "
157  @"of an entity already in use"));
158  _abstract = flag;
159 }
160 
165 - (BOOL) _isSubentityOfEntity: (NSEntityDescription *) otherEntity
166 {
167  NSEntityDescription * entity;
168 
169  for (entity = self; entity != nil; entity = [entity superentity])
170  {
171  if ([entity isEqual: otherEntity])
172  {
173  return YES;
174  }
175  }
176 
177  return NO;
178 }
179 
180 - (NSDictionary *) subentitiesByName
181 {
182  NSMutableDictionary * dict;
183  NSEnumerator * e;
184  NSEntityDescription * subentity;
185 
186  dict = [NSMutableDictionary dictionaryWithCapacity: [_subentities count]];
187  e = [_subentities objectEnumerator];
188  while ((subentity = [e nextObject]) != nil)
189  {
190  [dict setObject: subentity forKey: [subentity name]];
191  }
192 
193  return [[dict copy] autorelease];
194 }
195 
196 - (NSArray *) subentities
197 {
198  return _subentities;
199 }
200 
201 - (void) setSubentities: (NSArray *) someEntities
202 {
203  EnsureEntityEditable(_model, _(@"Tried to set sub-entities of an entity "
204  @"already in use"));
205  ASSIGN(_subentities, [[someEntities copy] autorelease]);
206 }
207 
208 
209 - (NSEntityDescription *) superentity
210 {
211  return _superentity;
212 }
213 
214 - (void) _setSuperentity: (NSEntityDescription *) entity
215 {
216  EnsureEntityEditable(_model, _(@"Tried to set super-entity of an entity "
217  @"already in use"));
218  _superentity = entity;
219 }
220 
221 
222 
223 - (NSDictionary *) propertiesByName
224 {
225  return [self filteredPropertiesOfClass: Nil];
226 }
227 
228 - (NSArray *) properties
229 {
230  return _properties;
231 }
232 
233 - (void) setProperties: (NSArray *) someProperties
234 {
235  EnsureEntityEditable(_model, _(@"Tried to set properties "
236  @"of an entity already in use"));
237  ASSIGN(_properties, [[someProperties copy] autorelease]);
238  [_properties makeObjectsPerformSelector: @selector(_setEntity:)
239  withObject: self];
240 }
241 
242 - (NSDictionary *) userInfo
243 {
244  return _userInfo;
245 }
246 
247 - (void) setUserInfo: (NSDictionary *) userInfo
248 {
249  EnsureEntityEditable(_model, _(@"Tried to set properties "
250  @"of an entity already in use"));
251  ASSIGN(_userInfo, [[userInfo copy] autorelease]);
252 }
253 
254 
255 
256 - (NSDictionary *) attributesByName
257 {
258  return [self _filteredPropertiesOfClass: [NSAttributeDescription class]];
259 }
260 
261 - (NSDictionary *) relationshipsByName
262 {
263  return [self _filteredPropertiesOfClass: [NSRelationshipDescription class]];
264 }
265 
266 - (NSArray *) relationshipsWithDestinationEntity:
267  (NSEntityDescription *) destEntity
268 {
269  NSMutableArray * array;
270  NSEnumerator * e;
271  NSRelationshipDescription * relationship;
272  Class relationshipClass;
273 
274  array = [NSMutableArray arrayWithCapacity: [_properties count]];
275  relationshipClass = [NSRelationshipDescription class];
276 
277  e = [_properties objectEnumerator];
278  while ((relationship = [e nextObject]) != nil)
279  {
280  if ([relationship isKindOfClass: relationshipClass] &&
281  [relationship destinationEntity] == destEntity)
282  {
283  [array addObject: relationship];
284  }
285  }
286 
287  return [[array copy] autorelease];
288 }
289 
290 // NSCopying
291 
292 - (id) copyWithZone: (NSZone *) aZone
293 {
294  NSEntityDescription * entity;
295 
296  entity = [[NSEntityDescription allocWithZone: aZone] init];
297 
298  [entity setName: _name];
299  [entity setManagedObjectClassName: _managedObjectClassName];
300  [entity setAbstract: _abstract];
301  [entity setSubentities: _subentities];
302  [entity _setSuperentity: _superentity];
303 
304  return entity;
305 }
306 
307 // NSCoding
308 
309 - (id) initWithCoder: (NSCoder *) coder
310 {
311  if ((self = [self init]))
312  {
313  if ([coder allowsKeyedCoding])
314  {
315  ASSIGN(_name, [coder decodeObjectForKey: @"Name"]);
316  _abstract = [coder decodeBoolForKey: @"Abstract"];
317  ASSIGN(_managedObjectClassName,
318  [coder decodeObjectForKey: @"ManagedObjectClassName"]);
319  ASSIGN(_properties, [coder decodeObjectForKey: @"Properties"]);
320  ASSIGN(_userInfo, [coder decodeObjectForKey: @"UserInfo"]);
321  ASSIGN(_subentities, [coder decodeObjectForKey: @"SubEntities"]);
322  _superentity = [coder decodeObjectForKey: @"SuperEntity"];
323  _model = [coder decodeObjectForKey: @"ManagedObjectModel"];
324  _modelRefCount = [coder decodeIntForKey: @"ModelReferenceCount"];
325  }
326  else
327  {
328  ASSIGN(_name, [coder decodeObject]);
329  [coder decodeValueOfObjCType: @encode(BOOL) at: &_abstract];
330  ASSIGN(_managedObjectClassName, [coder decodeObject]);
331  ASSIGN(_properties, [coder decodeObject]);
332  ASSIGN(_userInfo, [coder decodeObject]);
333  ASSIGN(_subentities, [coder decodeObject]);
334  _superentity = [coder decodeObject];
335  _model = [coder decodeObject];
336  [coder decodeValueOfObjCType: @encode(unsigned int)
337  at: &_modelRefCount];
338  }
339 
340  }
341  return self;
342 }
343 
344 - (void) encodeWithCoder: (NSCoder *) coder
345 {
346  if ([coder allowsKeyedCoding])
347  {
348  [coder encodeObject: _name forKey: @"Name"];
349  [coder encodeBool: _abstract forKey: @"Abstract"];
350  [coder encodeObject: _managedObjectClassName
351  forKey: @"ManagedObjectClassName"];
352  [coder encodeObject: _properties forKey: @"Properties"];
353  [coder encodeObject: _userInfo forKey: @"UserInfo"];
354  [coder encodeObject: _subentities forKey: @"SubEntities"];
355  [coder encodeObject: _superentity forKey: @"SuperEntity"];
356  [coder encodeObject: _model forKey: @"ManagedObjectModel"];
357  [coder encodeInt: _modelRefCount forKey: @"ModelReferenceCount"];
358  }
359  else
360  {
361  [coder encodeObject: _name];
362  [coder encodeValueOfObjCType: @encode(BOOL) at: &_abstract];
363  [coder encodeObject: _managedObjectClassName];
364  [coder encodeObject: _properties];
365  [coder encodeObject: _userInfo];
366  [coder encodeObject: _subentities];
367  [coder encodeObject: _superentity];
368  [coder encodeObject: _model];
369  [coder encodeValueOfObjCType: @encode(unsigned int)
370  at: &_modelRefCount];
371  }
372 }
373 
389 - (void) _addReferenceToManagedObjectModel: (NSManagedObjectModel *) aModel
390 {
391  // don't allow re-setting the owner like this
392  NSAssert(aModel != nil && (_model == nil || _model == aModel),
393  _(@"Attempted to forcefully change the reference from an entity "
394  @"to it's managed object model owner or ``nil'' model argument "
395  @"passed."));
396 
397  _model = aModel;
398  _modelRefCount++;
399 }
400 
401 - (void) _removeReferenceToManagedObjectModel: (NSManagedObjectModel *) aModel
402 {
403  NSAssert(_model == aModel, _(@"Attempted to forcefully remove the "
404  @"reference from an entity to it's managed object model by some other, "
405  @"unrelated model."));
406  NSAssert(_modelRefCount > 0, _(@"Attempted to underflow the "
407  @"reference count from an entity to it's managed object model."));
408 
409  _modelRefCount--;
410  if (_modelRefCount == 0)
411  {
412  _model = nil;
413  }
414 }
415 
416 @end