No question, put them in the database. Use ERXEnterpriseObjectCache to avoid needless repeated database trips.
Using the standard WO classes:
/**
* Creates a standard EO cache object for the passed entity name and
keypath for all objects of
* the entity that match restrictingQualifier. If restrictingQualifier is
null, all objects of this entity are
* cached.
*
* @param entityName name of the EOEntity for the instances that will be in
the cache
* @param keyPath key path of unique value in EOs
* @param restrictingQualifier EOQualifier restricting the set of objects
in the cache
* @param shouldFetchInitialValues true if the cache should be fully
populated on first access
* @return a standard EO cache object for the passed entity name and keypath
*/
public static ERXEnterpriseObjectCache createCache(String entityName,
String keyPath, EOQualifier restrictingQualifier, boolean
shouldFetchInitialValues) {
/** require [valid_entityName] entityName != null;
[valid_keyPath] keyPath != null;
**/
EOEditingContext ec = new EOEditingContext();
ec.lock();
try
{
EOObjectStoreCoordinator osc = (EOObjectStoreCoordinator)
ec.rootObjectStore();
osc.lock();
try
{
long timeout = // get this from a property
boolean shouldRetainObjects = true;
boolean shouldReturnUnsavedObjects = true; // Needed for
imports where new objects reference other new objects
ERXEnterpriseObjectCache cache = new
ERXEnterpriseObjectCache(entityName, keyPath, restrictingQualifier, timeout,
shouldRetainObjects, shouldFetchInitialValues, shouldReturnUnsavedObjects);
/**
* OK, things get nasty here. You HAVE been warned!
*
* The cache has an interaction with the EOEditingContext
fetchTimestamp()/defaultFetchTimestampLag(). After
* the objects have been fetched into the cache, if the
defaultFetchTimestampLag() passes before they are
* re-fetched, when they are faulted into a new editing context
(localInstanceOfObject), the snapshot will be discarded
* and the objects re-fetched, one by one. This rather
eliminates the value of the cache.
*
* There are a few options to fix this:
* - use a large defaultFetchTimestampLag() and ensure that all
the places that need fresh data use
* a fetch specification that refreshes re-fetched objects.
This also means that you must pre-fetch all
* the objects that need fresh data. This makes the
defaultFetchTimestampLag() rather useless to control
* data freshness.
*
* - use a large defaultFetchTimestampLag() and implement
ERChangeNotification to keep all the EOF stacks
* in sync. This ensures current data without needing to use
defaultFetchTimestampLag().
*
* - use a custom EODatabaseContext.delegate and implement the
delegate method
* databaseContextShouldFetchObjectFault(EODatabaseContext,
Object) to use the existing snapshot regardless of age.
* To implement this, the delegate will need to know that the
entity is being cached. This can be done by setting
* a flag in EOEntity.userInfo in this method.
*
* - make the objects as "Cache in Memory" in the EOModel. The
large drawback of this is that the objects will never
* be refreshed. Refreshing fetch specifications do not
affect entities cached in memory.
*
* - mark the snapshots of the cached objects as expiring at
some time in the distant future. As they expire from the
* cache they will be re-fetched and refreshed from the
database. This option was chosen as it more closely matches
* what should happen. It does require access to a protected
method in EODatabase. It is possible that future
* versions of WebObjects will break this implementation, but
there should be some way of achieving the result.
*/
EOEntity entity = EOUtilities.entityNamed(ec, entityName);
EODatabaseContext dbContext =
EOUtilities.databaseContextForModelNamed(ec, entity.model().name());
EODatabase database = dbContext.database();
NSArray objectsInCache = cache.allObjects(ec);
for (int i = 0; i < objectsInCache.count(); i++)
{
EOEnterpriseObject eo = (EOEnterpriseObject)
objectsInCache.objectAtIndex(i);
// Sets the expiration timestamp for the snapshot to
NSTimestamp.DistantFuture.getTime()
_setTimestampForCachedGlobalID().invoke(database,
ec.globalIDForObject(eo));
}
return cache;
}
catch (Exception e)
{
throw new ExceptionConverter(e);
}
finally
{
osc.unlock();
}
}
finally
{
ec.unlock();
ec.dispose();
}
/** ensure [valid_result] Result != null; **/
}
private static Method _setTimestampForCachedGlobalID = null;
/**
* Hack to access protected method in EODatabase.
* @return Method for protected void
_setTimestampForCachedGlobalID(EOGlobalID gid)
*/
private static Method _setTimestampForCachedGlobalID()
{
synchronized (GenericRecord.class)
{
if (_setTimestampForCachedGlobalID == null)
{
try
{
_setTimestampForCachedGlobalID =
EODatabase.class.getDeclaredMethod("_setTimestampForCachedGlobalID",
new Class[] {EOGlobalID.class});
_setTimestampForCachedGlobalID.setAccessible(true);
}
catch (Exception e)
{
throw new ExceptionConverter(e);
}
}
}
return _setTimestampForCachedGlobalID;
}
Chuck
On 2011-11-24, at 12:45 PM, Pascal Robert wrote:
> I want to add some "system preferences" to SimpleBlog, for things like number
> of comments per page, if comments are moderated or not, etc. I'm wondering
> what's the best way to handle that. I was thinking of using a plist and read
> it at "boot time" so that the preferences are in memory, and writing the file
> when a pref changes. The problem with this solution is that the file will
> have to be outside the .woa since the preferences have to survive a upgrade.
> And if a server have more than one SimpleBlog instance (e.g., "multi
> tenants"), it would have to be different files.
>
> The other solution would be to store the preferences in the database. In the
> case of multi tenants, each instance would have to have it own databases. The
> potential problem would be a performance one, we would need to call EOF every
> time a preference is needed (for display groups, etc.). Sure, I'm not talking
> about high performance system here, but it would be great to show best
> practices.
>
> So, how would you manage this?
> _______________________________________________
> Do not post admin requests to the list. They will be ignored.
> Webobjects-dev mailing list ([email protected])
> Help/Unsubscribe/Update your Subscription:
> http://lists.apple.com/mailman/options/webobjects-dev/chill%40global-village.net
>
> This email sent to [email protected]
--
Chuck Hill Senior Consultant / VP Development
Practical WebObjects - for developers who want to increase their overall
knowledge of WebObjects or who are trying to solve specific problems.
http://www.global-village.net/products/practical_webobjects
smime.p7s
Description: S/MIME cryptographic signature
_______________________________________________ Do not post admin requests to the list. They will be ignored. Webobjects-dev mailing list ([email protected]) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com This email sent to [email protected]
