Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: Is ExternalId permanent?

2 views
Skip to first unread message

Dmitriy Nagirnyak

unread,
Jan 19, 2008, 2:05:38 AM1/19/08
to
Hello Steven,

> the class identifier part of the ExternalId might change if you edit
> the model and evolve the database schema
>
Yes. That is the case.
I use custom mapping and define the class IDs.
Then I use modified external id service that use only that IDs.
So it is never changed.

If you want I can send you the library and give some details.

Cheers,
Dmitriy Nagirnyak
http://dcportal.argocomputing.com.au
http://dnagir.blogspot.com


Steven Stewart

unread,
Jan 19, 2008, 2:00:22 AM1/19/08
to
I want to be able to be able to pass an ExternalId as a parameter in a URL,
for example to identify a particular Company to show detail information for.
Then users can bookmark the page to always get to that Company's detail
page.

I vaguely remember from the last time I did much ECO programming (ECO II)
that the class identifier part of the ExternalId might change if you edit
the model and evolve the database schema. It doesn't make much sense to me
that an existing ExternalId could change in this way. Is my memory
incorrect about this, and is the ExternalId an appropriate way to
permanantly identify an object?

Thanks -- Steve

Peter Morris [CapableObjects]

unread,
Jan 19, 2008, 5:13:21 AM1/19/08
to
ExternalID is a good way to identify an object in two scenarios

01: A new object in the same EcoSpace instance that has not yet been saved
to the DB.
02: An existing object in any EcoSpace where the object has been saved, but
only until the model changes.

The problem is that Google etc will bookmark the URL past the life of the
application, so when someone uses that URL at a later date the model may
have been changed.

In this case the best way to uniquely identify something is to have a
property on your class of type AutoInc, and to use this when locating an
object via URLs.

Pete


Steven Stewart

unread,
Jan 20, 2008, 11:56:54 PM1/20/08
to
> In this case the best way to uniquely identify something is to have a
> property on your class of type AutoInc, and to use this when locating an
> object via URLs.

Thanks Pete. That's what I was afraid of.

Is at least the ECO_ID portion of the ExternalID guaranteed to be permanent?
If so, is there a way to get the ECO_ID value from ECO? (Yes, I know I
could just parse the ExternalID, but that seems like cheating.) And, if so,
is there a way to reconstruct an ExternalId from the ECO_ID and the current
ECO_TYPE value from the class so I could once again do an ObjectForID?

Seems a waste to define an extra attribute for an AutoInc when ECO already
keeps unique fields for (almost) the same purpose. Also, I note that the
ECO_ID is an indexed field in the database, so I assume ECO does an
ObjectForId lookup very efficiently. Creating my own ID fields would also
require that I create and run special code or SQL for a database to create
an index for the AutoInc fields, and creating special database code is not
"The ECO Way." Or, does ECO anticipate our needs and automatically index
AutoInc fields?

Also, it seems inefficient for ECO to be renumbering ECO_ID and ECO_TYPE
fields all over a large database whenever you evolve a model change. I
can't think of any reason ECO would really need to do that except if you
change how an inheritance relationship is to be stored in the database.
(Hmmm... Would ECO actually move the data for you in that case? Seems
unlikely, but I digress.)

Thanks -- Steve

Peter Morris [CapableObjects]

unread,
Jan 21, 2008, 3:40:28 AM1/21/08
to
> Is at least the ECO_ID portion of the ExternalID guaranteed to be
> permanent?

Yes.


> If so, is there a way to get the ECO_ID value from ECO?

I have never tried this myself, but I think I have seen someone say that
they added a modeled property like this to their class and it worked:

ECO_ID : Int
SaveAction = DbAssign


> And, if so, is there a way to reconstruct an ExternalId from the ECO_ID

I think that the following might work, it's worth trying anyway....

IClass ecoClassifier =
EcoSpace.TypeSystem.GetClassifierByType(typeof(Person));
int classIndex = ecoClassifier.InternalIndex;


> ECO_TYPE value from the class so I could once again do an ObjectForID?

The first part of the ExternalID is not the ECO_TYPE. The ECO_TYPE remains
the same in the DB whereas the ClassIndex is the index within the model.
The purpose of this is to tell the persistencemapper which class the ID is
for.


> Seems a waste to define an extra attribute for an AutoInc when ECO already
> keeps unique fields for (almost) the same purpose.

Depends on the object. For an Article I would add an auto-inc, same for
Invoice, PurchaseOrder, etc. For a Person however a sequencial number is
meaningless.

> Creating my own ID fields would also require that I create and run special
> code or SQL for a database to create an index for the AutoInc fields, and
> creating special database code is not "The ECO Way." Or, does ECO
> anticipate our needs and automatically index AutoInc fields?

No it doesn't create any indexes at all (except for the primary key). You
are free to add indexes to your DB structure, you just have to drop/recreate
them if you want to rename a table or column, just as you would if you were
doing it manually.

> Also, it seems inefficient for ECO to be renumbering ECO_ID and ECO_TYPE
> fields all over a large database whenever you evolve a model change

No, that doesn't happen. The ECO_TYPE and ECO_ID never change in the DB.
This is how it works......


<Class> ! <ID>

The <Class> part is the index of the class within the model. This value
doesn't go as far as your database. It is used to communicate object
identity between the EcoSpace and the PersistenceMapper (remember, for
custom mapped persistence to an existing DB there probably isn't an ECO_TYPE
at all). It's just a way of saying to the PM "The class type I want is
PERSON". The PM has access to the same model information as the EcoSpace,
whether it is local or remote, so it knows that 23 is PERSON. When it needs
to update the DB or fetch objects it knows that it is dealing with PERSON
and therefore knows which tables to join.

The ECO_TYPE is used when you retrieve objects in a less explicit way. For
example "SomeAbstractClass.allInstances". ECO would determine which type of
object to create in the EcoSpace cache by looking at the actual type of
object.

They are not related at all :-)

> (Hmmm... Would ECO actually move the data for you in that case? Seems
> unlikely, but I digress.)

As I said, it doesn't change.

I think you can get the first part of the ExternalId like so........

IClass ecoClass = EcoSpace.TypeSystem.GetClassifierByType(typeof(Person));
return ecoClass.InternalIndex;

Just out of curiousity, what would you think of an ExternalId that was
longer but permanent? For example....

www.mysite.com/showarticle.aspx?id={classid}!1234

where classid is 22 characters made up of
a..z
A..Z
0..9
- and _


With the option of replacing the externalid provider if you don't like the
look of it (which is possible now, but I haven't checked how).

Pete

Efim Mett

unread,
Jan 21, 2008, 3:17:04 PM1/21/08
to

"Peter Morris [CapableObjects]" <peter[dot]morris(at)capableobjects.com>
schrieb im Newsbeitrag news:4794...@newsgroups.borland.com...

> > Is at least the ECO_ID portion of the ExternalID guaranteed to be
> > permanent?
>
> Yes.
>
For now only if the object is persisted. For transient or not yet persisted
objects the part of EXternalID after ':' increases after each access. That
is probably a bug though


Peter Morris [CapableObjects]

unread,
Jan 21, 2008, 3:28:35 PM1/21/08
to
> For now only if the object is persisted. For transient or not yet
> persisted
> objects the part of EXternalID after ':' increases after each access. That
> is probably a bug though

I strongly suspect it is, have you reported it yet?


Efim Mett

unread,
Jan 21, 2008, 3:49:44 PM1/21/08
to

"Peter Morris [CapableObjects]" <peter[dot]morris(at)capableobjects.com>
schrieb im Newsbeitrag news:4795...@newsgroups.borland.com...
Yes


Steven Stewart

unread,
Jan 21, 2008, 11:21:36 PM1/21/08
to
Thanks again, Pete.

> Just out of curiousity, what would you think of an ExternalId that was
> longer but permanent? For example....

Not sure what you have in mind here -- maybe the class name (except for the
'-')? Of course, the class name might change as the model evolves. Anyway,
length doesn't matter quite so much to me as permanence. URL compatibility
would also be a nice-to-have. For example, GUIDs make convenient IDs for
certain purposes, but they are unwieldy in a URL and next to impossible for
humans to make use of. An AutoInc would be fine, but using the ECO_ID is
even better because it is already there, already indexed, and ready to make
use of in an ExternalId. For my purposes I should always know the class of
the object I'm looking up, so with the trick you provided I should be able
to pass just the ECO_ID as a parameter and reconstruct the ExternalId in
code on the fly.

What I really want is for ECO to provide a PermanentId service, just like
the ExternalId service, so I don't have to do that little bit of extra
coding. (Or preferably, make the ExternalId permanent, but I guess that's
not likely.) Also, I'll bet a lot of ECO users assume the ExternalId is
permanent. This seems like a common need for your users -- I always need a
permanent ID for the kind of applications I write. But as long as I can
avoid having to create my own permanent ID field for my ECO classes, I can
keep my model "cleaner and leaner", and (more importantly) stay more
database agnostic because I don't have to write any database code to define
additional indexes.

Which brings up another need -- for ECO to provide a database agnostic way
to define additional indexes. But that is for another thread and another
day...

Thanks -- Steve

Per Bakkendorff

unread,
Jan 22, 2008, 3:39:02 AM1/22/08
to
Steven Stewart wrote:

>
> Is at least the ECO_ID portion of the ExternalID guaranteed to be
> permanent? If so, is there a way to get the ECO_ID value from ECO?
> (Yes, I know I could just parse the ExternalID, but that seems like
> cheating.) And, if so, is there a way to reconstruct an ExternalId from
> the ECO_ID and the current ECO_TYPE value from the class so I could once
> again do an ObjectForID?

I parse the IDForObject, and strip the number before the colon, and send
this ID to an external system. (Beware of transient objects, and objects
that are not saved as Efim mention).
When get data back, I locate the the object again by just getting the
internal index and put that (plus the colon) in front of the ID I'm
trying to locate. Send it to ObjectForID function, and I have my object
again.
Works great - and have been working for over a year now, in a production
system.

Per

Peter Morris [CapableObjects]

unread,
Jan 22, 2008, 4:48:04 AM1/22/08
to
How do you identify which class the ID identifies?


Peter Morris [CapableObjects]

unread,
Jan 22, 2008, 4:47:22 AM1/22/08
to
> Not sure what you have in mind here -- maybe the class name (except for
> the '-')? Of course, the class name might change as the model evolves.

Noooo, that would not be permanent :-)

I wrote a small routine to convert the class's element GUID in the model
which never changes into a string of the following characters
a..zA..Z0..9-_

Permanent + URL friendly, but 22 characters long and could potentially spell
a rude word by accident :-)


>An AutoInc would be fine

You can't do that because the auto-inc value would not be unique across
packages. If you used one of my packages in your app the ID's would clash.


> but using the ECO_ID is even better because it is already there,

Two problems with that approach:
01: You need access to the DB, when using remote persistence it would not be
available.
02: Who is to say there is such a thing in the persistence? ECO persistence
is abstract, you could in theory persist to a web service, OOP Database, or
even an XML file (which you can).


> Also, I'll bet a lot of ECO users assume the ExternalId is permanent.

I once did. I have seen others do it too.

Pete


Dmitriy Nagirnyak

unread,
Jan 22, 2008, 8:51:11 AM1/22/08
to
Hello Guys,

> How do you identify which class the ID identifies?
>

I use 2 methods bundled together:
1. GetDBKey - return value of PK as a string.
2. GetObjectById - returns ECO object by integer PK (for now) and type.


Sample (.NET 1.1 - would look much better in 2.0):
===================
User u = GetUser();
string strId = EcoUtils.GetDBKey(u);

int intId = Convert.ToInt32(strId);
u = (User)EcoUtils.GetObjectByID(EcoSpace, intId, typeof(User))
===================


My code itself is tight to ECOIIIPatches, but can be, of course, rewritten
better.
(Thanks to Jonas for helping with it)

=========================================================
public static string GetDBKey(IObjectProvider obj)
{
if (obj == null)
throw new ArgumentNullException("obj");
IObject instance = obj.AsIObject();

ExternalIdServiceImpl extIdService = EcoServiceHelper.GetExternalIdService(instance)
as ExternalIdServiceImpl;
if (extIdService == null)
throw new InvalidOperationException( string.Format("ExternalIdService
is invalid. It should be of {0} type.", typeof(ExternalIdServiceImpl).ToString())
);

Locator loc = null;
if ((instance != null) && (instance.ObjectInstance != null))
loc = extIdService.ObjectRepresentationProvider.LocatorForIObject(instance.ObjectInstance);

if (loc == null)
throw new NullReferenceException("GetDBKey. Locator is null.");

ObjectId Id = extIdService.Cache.GetIdByLocator(loc);
if (Id == null)
throw new InvalidOperationException("Obtained ObjectId is null which
is incorrect.");

return Id.Key.ToString();
}

=========================================================

public static IObjectInstance GetObjectByID(IEcoServiceProvider sp, int
key, Type ecoObjectType)
{
ITypeSystemService typeSystemService = EcoServiceHelper.GetTypeSystemService(sp);
Debug.Assert(typeSystemService != null);
IEcoTypeSystem typeSystem = typeSystemService.TypeSystem;

IClass c = typeSystem.GetClassByType(ecoObjectType);

ExternalIdServiceImpl extIdService = EcoServiceHelper.GetExternalIdService(sp)
as ExternalIdServiceImpl;
if (extIdService == null)
throw new InvalidOperationException( string.Format("ExternalIdService
is invalid. It should be of {0} type.", typeof(ExternalIdServiceImpl).ToString())
);

Locator loc = extIdService.Cache.GetEnsuredLocatorById(new DefaultId(key,
c.EcoClass.InternalIndex));

IObjectInstance objectInstance = extIdService.ObjectRepresentationProvider.IObjectForLocator(loc);
if (objectInstance == null)
return null;

if (objectInstance.AsObject != null && objectInstance.Deleted)
return null;
return objectInstance;
}

=========================================================

Hope this will help somebody someday :).

Peter Morris [CapableObjects]

unread,
Jan 22, 2008, 9:19:34 AM1/22/08
to
What I mean is how does Per Bakkendorf translate "123" into an object type +
123?


Peter Morris [CapableObjects]

unread,
Jan 22, 2008, 10:47:39 AM1/22/08
to

Steven Stewart

unread,
Jan 22, 2008, 4:01:38 PM1/22/08
to
Peter --

>>An AutoInc would be fine
>
> You can't do that because the auto-inc value would not be unique across
> packages. If you used one of my packages in your app the ID's would
> clash.

Not sure I follow your point -- don't see what packages have to do with it.
The AutoInc would only be unique within a class/table. For my purposes that
is good enough. I can create and bookmark URLs like:
(1) www.myapp.com/CompanyDetail.aspx?AutoIncID=123
or
(2) www.myapp.com/CompanyDetail.aspx?ECO_ID=456

For (1) I would create OCL to select for the Company object with
AutoIncID=123. For (2), which is my preference, I would use your code
suggestion to create an ExternalId and then use that in a call to
ObjectForId. Anything wrong with my logic?


>> but using the ECO_ID is even better because it is already there,
>
> Two problems with that approach:
> 01: You need access to the DB, when using remote persistence it would not
> be available.
> 02: Who is to say there is such a thing in the persistence? ECO
> persistence is abstract, you could in theory persist to a web service, OOP
> Database, or even an XML file (which you can).

Perhaps you're saying I shouldn't use the idea of creating an ECO_ID
attribute with a SaveAction=DbAssign property in my model? I wasn't really
considering that.

Remote persistance is a topic I haven't tackled yet. But however the data
is stored, doesn't ECO always provide a way to retrieve an object via the
ExternalId? What I want to do is use the stored ECO_ID from the URL, plus
your code that gets the current class ID, to create a valid ExternalId, and
then tell ECO to find the object using the ExternalId. However ECO finds it
is, and should be, a black box to me. All the better not to be fooling
around with AutoInc fields and database code to index them. As I understand
it, ObjectForId should always work regardless of the persistance mechanism.
Am I wrong?

Thanks -- Steve


Steven Stewart

unread,
Jan 22, 2008, 4:17:48 PM1/22/08
to
> I parse the IDForObject, and strip the number before the colon, and send
> this ID to an external system.

> When get data back, I locate the the object again by just getting the

> internal index and put that (plus the colon) in front of the ID I'm trying
> to locate.

This is probably a small point, but the reason I said earlier I'd prefer not
to directly parse or reconstruct the IdForObject string is because you are
then depending on the format of the ID to be consistent in new ECO versions.
It is concievable that they could change or extend the format in the future.
(Murphy's Law) But they probably won't. :-)

Anyway, it appears that there are no ECO-provided functions to do this, so
your idea is what I'll probably use too.

Thanks -- Steve

Dmitriy Nagirnyak

unread,
Jan 22, 2008, 5:32:51 PM1/22/08
to
Hello Peter,

> What I mean is how does Per Bakkendorf translate "123" into an object
> type + 123?
>

As far as I have understood he just combines two strings and gets the ID
in "XX:YY" format.
Then uses IdForObject to get the object. Am I right, Per?

Why not just use something like my GetObjectById to get the actual object...

Generally it seems CLASSID and OBJECTID ("CLASSID:OBJECTID") are useles as
separate ones in terms of using it as ExtenralID.
This is because of there's no way (at least I don't see) to restore the correctly
formatted string (having CLASSID and OBJECTID) from IExternalIdService.
IExternalIdService only allows getting the object by string ID and vice versa,
but not create/format/etc that string ID.

Dmitriy Nagirnyak

unread,
Jan 22, 2008, 5:33:18 PM1/22/08
to
Hello Peter,

> http://mrpmorris.blogspot.com/2008/01/externalid-is-not-related-to-eco
> type.html
>
This is very useful description.
Thanks.


Steven Stewart

unread,
Jan 23, 2008, 3:24:16 AM1/23/08
to
Dmitriy --

Thanks for the code. It sounds like it does exactly what I want. However,
I'm not familiar with the Locator class and related methods. I just found a
discussion of that in Schmid's book, but I don't think I've read about it
anywhere else. I'll study this and consider trying it soon.

Thanks -- Steve

Per Bakkendorff

unread,
Jan 23, 2008, 1:32:20 PM1/23/08
to
Peter Morris [CapableObjects] wrote:
> What I mean is how does Per Bakkendorf translate "123" into an object type +
> 123?
>

When I get the data back from an external source, they return my
original objectID (ECO_ID) and I then fetch the internal index for that
class using the following code:

function MyClassHelper.GetObjectClassID: Integer;
begin
if FObjectClassID = 0 then
FObjectClassID:=
(FProvider.GetEcoService(typeof(ITypeSystemService)) as
ITypeSystemService).TypeSystem.AllClasses.GetItemByName('ObjectClass').EcoClass.InternalIndex;
Result:= FObjectClassID;
end;

That ObjectClassID is then combined with the ObjectID (ECO_ID) like:

with (FProvider.GetEcoService(TypeOf(IExternalIDService)) as
IExternalIDService) do
Result:= ObjectForID(GetObjectClassID.ToString + ':' +
id).AsObject as ObjectClass;

Now please don't tell me this will fail in the future :) Works like a
charm, until now (and has for over a year now) ;)

Per

0 new messages