Mike Cole's .NET Blog

ObjectSpaces - thin?

One of the most innovative things about ObjectSpaces is the fact that your business entities are not required to inherit from any base class. 

 

With every persistence framework I have worked with – this has always been a requirement.  As in this example, EntityBase would provide your O/R mapping and persistence functionality:

 

public class Employee : EntityBase

{

       private int _ID;

       private string _fullName;

             

       public int ID {get {return _ID;} set{_ID = value;}}

       public string FullName{get {return _fullName;} set{_fullName = value;}}

       public Employee()

       {

       }

}

 

 

By not requiring use of a base class – I think Microsoft has done a great job keeping ObjectSpaces as thin and transparent as possible.

 

How was this accomplished?

 

The ObjectSpace classes (driven by map files) consume your custom classes, instead of providing functionality through inheritance.

 

For example to retrieve an employee,

 

ObjectSpace os = new ObjectSpace("map.xml", conn);

ObjectReader reader = os.GetObjectReader(new ObjectQuery(typeof(Employee), "ID = 1234’"));

Employee myEmp = (Employee) reader.Current;

 

Very nice. However, you might say… how is this considered thin? I’m used to instantiating business objects as easily as this:

 

A)  Employee myEmp = new Employee(id);

OR

B)  Employee myEmp = Employee.GetByID(id);

 

Well, the good news is… if you have been using a factory design pattern to instantiate your biz objects (as in B) – then you will be able to encapsulate all of the ObjectSpace classes within your static method (GetByID):

 

Similar to this,

 

public class Employee

{

private int _ID;

       private string _fullName;

             

       public int ID {get {return _ID;} set{_ID = value;}}

       public string FullName{get {return _fullName;} set{_fullName = value;}}

       public Employee()

       {

       }

 

       public static Employee GetById(int ID)

       {

              ObjectSpace os = new ObjectSpace("map.xml", conn);

       ObjectReader reader = os.GetObjectReader(new ObjectQuery(typeof(Employee), String.Format("ID = {0}", ID)));

              return((Employee)reader.Current);

       }

}

 

So, if you have been using a factory creational pattern – perhaps the developers consuming your business objects need not be aware of a conversion to ObjectSpaces at all…. Seems pretty tight to me. Of course, I have not seen examples of inserts/updates using ObjectSpaces yet.  Please comment! 

 

-Mike

 

PDC presentation  , Lucas Bolonese on ObjectSpaces.

Comments

Thomas Tomiczek said:

::One of the most innovative things
::about ::ObjectSpaces is the fact that your
::business entities are not required to
::inherit from any base class.

This is not innovative. There are dozens of persistence frameworks around allowing the same.

The issue is that due to this they require literally pages of code to get up in functionality onto what other persistence frameworks give oyu literally for free. Heck, they dont even raise change events in an intelligent way.

This is a design decision, and most find this simply not worth it.

::With every persistence framework I have
::worked with – this has always been a
::requirement.

I strongly suggest you work with more than one or two persistence frameworks before making hugh statements about what is innovative.

* OJB.NET does not require a base class.
* In the java world, not requiring a base class is pretty normal. But then, there is a way to change the bytecode of a class while it is loaded, which is not possible with .NET.

::So, if you have been using a factory
::creational pattern – perhaps the developers
::consuming your business objects need not be
::aware of a conversion to ObjectSpaces at
::all….

Yes, and what do they gain with this?

Answer: pretty much nothing. A persistent object is NOT a regular object, it follows different rules. I prefer having developers aware that they are hitting the database. A non-introsive API is better than no API. There are enough (cough) smart (cough) developers out there that will ruin every architecture even IF you give them clues.

Look at your example:

::Well, the good news is… if you have been
::using a factory design pattern to
::instantiate your biz objects (as in B) –
::then you will be able to encapsulate all of
::the ObjectSpace classes within your static
::method (GetByID):

I dont like this pattern at all. Why should an object know how to get itself by ID? There is this thing called responsibility, and you are just breaking it into small pieces and making gulash out of them. What if you need the object by some other condition? Go back to the developers of the object library (normally other people than the guy writing the frontend) and having them add a method?

I definitly prefer to express my queries where they are decided - normally in the front end. Simply becaue this is what de-coupling is all about. So I can keep the business objects in a separate DLL and reuse them and dont have to deal with literally hundreds of search methods trying to outguess how the objects will be queried for (and this can vary a LOT). This way y business class is small, and I dont add hundreds of little funny search methods to it.

Besides, btw, your search method is as bad as it can be, rereading the schema file on every get :-) But I take this is because it is a sample.
# December 11, 2003 4:29 PM

Drew Marsh said:

I'd argue that there's nothing wrong with requiring a base class, but that argument happens day in and day out in the O/R world, so I'll skip it. ;)

However, I did want to point out one thing. With static methods, like your Employee::GetId, what if you want the object to be part of a transaction? This method is always getting the object from a totally diff. ObjectSpace instance which means it's not going to be included in the transaction of the current object space. If you stayed with the static pattern, you'd always need to pass in an ObjectSpace instance as a parameter which the static method could use to retrieve the Employee object. However, then you run into issues where what if the ObjetSpace passed isn't configured for the Employee object? It gets messy really quick. The best thing to do is to always design a system class, say EmployeeSystem, that contains a private instance of an ObjectSpace and provides basic fetching/updating routines for entities that live within the system, such as Employee, as instance methods. The system then manages the lifetime of the ObjectSpace, loading of the configuration is managed in one place and transaction can be controlled by providing a custom transaction control implementation that basically delegates to the underlying ObjectSpace instance. This also has an added benefit of providing an extra level of indirection which can better abstract you from whatever ORM layer you've chosen.
# December 11, 2003 5:00 PM

Mike Cole said:

Cripes! I get ripped a new one by Mr. Thona Software O/R mapper tool expert.

[Thomas T writes]
I strongly suggest you work with more than one or two persistence frameworks before making hugh statements about what is innovative.

Did I make a huge statement about what was innovative? I simply opened with a complement to a technology that I was discussing, inviting comments -- I think not deserving of your personal attack.

[Thomas T writes]
Yes, and what do they gain with this?

What do they gain? The ability to introduce a new technology without having to re-write thousands of lines of code to support yet another data access technology. I’m simply trying to highlight the efforts made to keep additions to this evolving framework thin.

[Thomas T writes]
I definitly prefer to express my queries where they are decided.

That’s great. You miss my point entirely. The point is that a factory method can help encapsulate the complexity of actually creating the object. I can do another example w/a factory method that takes a complex query – and then you can express your query wherever you like.

[Thomas T writes]
I definitly prefer to express my queries where they are decided - normally in the front end. Simply becaue this is what de-coupling is all about.

Come on, that’s not what de-coupling is ALL about. In any case, what you’ve done in lowered coupling (a good thing) – but you’ve also lowered cohesion (a bad thing)… An object that knows all the different ways to instantiate & retrieve itself is a highly-cohesive object (at least it’s a contributing factor). You’ve pointed out this same object is more coupled to its consumers. Yes it is.

Assigning object responsibilities such that cohesion remains high and coupling remains low is the challenge. AND it is also not at ALL the point of this post. Thanks for (trying) to beat me up over it.

[Thomas T writes]
I prefer having developers aware that they are hitting the database

Super. Enjoy that.
# December 11, 2003 6:02 PM

Justin Rudd said:

A comment -

I don't like the mapping XML files and the reason I don't is because of lazy loading. They lead you into a false sense of security. They lead you to believe you won't have to change your object model.

Your example is very simplistic. What if Employee had an ArrayList that contains all their direct reports which in turn are Employee objects? If you don't use ObjectSpaces' special lazy load collection, you're query will be nasty and could require many trips to the database. So even though you have an XML mapping file you also have to change your object model.

Now this is based off just seeing the PDC slides and examples. I haven't actually used ObjectSpaces extensively. Personally I'm trying to get away from Domain Models for RETRIEVING data. I like using sprocs (or dynamic SQL) that retrieves all (or at least most) of the data that is needed for a page.
# December 11, 2003 8:06 PM

Paul Wilson said:

The following article has examples of inserts, updates, and deletes also: http://authors.aspalliance.com/paulwilson/articles/?id=21. I see pros and cons in each of the different o/r mappers I've played with.
# December 11, 2003 9:06 PM

TrackBack said:

# December 11, 2003 11:07 PM

Mike Cole said:

[Justin Rudd writes]
"Your example is very simplistic. What if Employee had an ArrayList that contains all their direct reports which in turn are Employee objects? If you don't use ObjectSpaces' special lazy load collection, you're query will be nasty and could require many trips to the database."

Well, I know. The example was simple on purpose. The functionality you describe, though, would be easy to add. Something like this... where Query, passed in could be "EmployeeBossId = XX"...

public static EmployeeList GetEmployees(string Query)
{

ObjectSpace os = new ObjectSpace("map.xml", conn);
ObjectSet set = os.GetObjectSet(new ObjectQuery(typeof(Employee), Query));
return((EmployeeList)set);
}

Of course I'm not suggesting any of this is best practice.... I'm just saying that it is possible to encapsulate the ObjectSpace stuff so it can be inserted with low impact into an existing application.

You do make a good point. Its not low-impact to convert your contained collections to a new class:
public ObjectList EmployeeList = new ObjectList();

But I dont think you need to...if you currently implement Just-In-Time instantiation, of child collections... just keep doing it the same way... your property calls the method above only if the collection is not loaded....


# December 12, 2003 5:00 PM

TrackBack said:

^_^,Pretty Good!
# April 10, 2005 5:46 AM

ObjectSpaces - thin? said:

Pingback from  ObjectSpaces - thin?

# November 26, 2007 3:54 PM
Leave a Comment

(required) 

(required) 

(optional)

(required)