Object-Relational Mapping

by iatanasov 20. July 2007 05:54

Introduction

 

Currently, Object-Relational mapping is probably the hottest topic of discussion on the internet in terms of the various software development circles. With all the hype surrounding ORM, it is easy to forget the why?. Why does ORM exist? It would seem that ORM has become somewhat of a religious war. One can only wonder if the ORM war will have people in the future asking a why? The focus of Object-Relational mapping is to solve the object-relational impedance mismatch. I.e. the object model does not equal the relational model and this is considered by many to be a problem. There are those that have subscribed to the viability of ORM as a persistence strategy, and there are those that have not. Some have questioned whether the object-relational impedance mismatch is a problem at all. Others argue that the object-relational impedance mismatch issue is being solved on the wrong side of the equation. I.e. there are those that advocate the use of Object-Oriented databases as a solution and not ORM. The fact that ORM has created so much attention and heated debate implies that there is something of importance or at least perceived importance. I leave it up to you to decide. That something deserves a closer inspection to separate the hype from the fact. The aim of this article is to encompass important a view for and against ORM. By so doing, it is intended to establish a different, or at least more informed, perception of ORM regardless of what the current perception may be.

 

Intent

 

To be fair, the topic of Object-Relational Mapping requires a book to address all the matters relating to it in its entirety. I provide just enough information in this article to allow one to consider ORM from a pragmatic perspective.

 

Object-Relational Mapping as a persistence strategy is both a statement and a question. In the first instance, I am implying that ORM is a persistence strategy. In other words, ORM is a viable technology in terms of satisfying ones persistence requirements. In the second instance, I am questioning ORM as a persistence strategy. I.e. Is ORM a viable solution in terms of satisfying ones persistence requirements. The focus of this article is not on the best ORM tools that are available. Best is at best transient and what is best today may not be whats best tomorrow. Instead, the focus is on ORM at a conceptual level. The reason that I have chosen to focus my attention at a conceptual level is due to the nature of change. ORM tools will appear, change, disappear and reappear. Technology will evolve and so will ORM tools. I consider the concepts behind ORM to be of far more significance and value. This allows one to view ORM in a pragmatic and hopefully unbiased view. Therefore, the intent of this article is to view ORM at a conceptual level, in an unbiased manner, and assume a technology agnostic approach.

 

For the purpose of clarity, the intent of this article is further summarized to be as follows:

 

  • Description of ORM
    • What is ORM?
    • Why does it exist?
    • In what form does it exist?
    • What are the problems associated with ORM?

  • Viability of ORM as a persistence strategy
    • Discussion on the requirements of a persistence strategy. Determining how well if at all ORM satisfies persistence requirements.
    • Reusability
    • Maturity
    • Time and Cost
    • Architecture

 

  • Choosing an ORM
    • Commercial vs. Open Source vs. In-house

 

  • Succeeding with ORM

 

Failing with ORM

Object-Relational Mapping

 

Often, a good way of understanding what something does, is to understand the reason for its existence. I.e. why does it exist? In terms of enterprise software development, most if not all software systems deal with getting data in and out of a data store. In this context the form of data store is unimportant. What is important is how one deals with the data store persistence. Data persistence implies the concept of persisting and retrieving data. It is a common and recurring development challenge. For those that are familiar with design patterns, the aforementioned statement should sound oddly familiar. Design patterns, at their simplest definition, are tried and tested solutions to common and recurring challenges. Therefore, is there or are there design patterns to deal with data persistence. Yes, there are many patterns that one might employ to deal with the data persistence challenge. Is ORM such a design pattern? ORM may use many design patterns to achieve its end. Whether it in and of itself is a pattern is probably a discussion best left to another article or forum. ORM is a technique that one might choose as a data persistence strategy. ORM is a solution, not the solution. It does help address a common development challenge, that being of data persistence. The popular term to describe the data persistence issue is that of the object-relational impedance mismatch. The question that arises is whether the impedance mismatch is really an issue. The Java development community seems to have adopted ORM well before any of the other development communities. I used the word seem as I have not encountered all development communities and therefore cannot say with certainty that this is the case. The Microsoft development community has chosen to ignore the object-relational mismatch until recently. I say recently because there only seems to be a boom in terms of the availability of ORM tools in recent times. I am not, however, implying that Microsoft has chosen to ignore the mismatch issue. Before continuing the discussion of ORM, the following points are highlighted in terms of understanding the definition of ORM.

 

  • It provides a way to resolve the object-relational impedance mismatch. This object-relational impedance mismatch is considered to be the core problem.
  • It is a technique for converting data between a relational database and an object-oriented programming language
  • It is an abstraction of data persistence code
  • The result of an ORM implementation is often likened to that of a virtual object database.
  • ORM provides us with database independence 

To further elaborate on what ORM is, I discuss ORM in terms of the following challenges:

 

  • Core Challenge
  • Conceptual Challenge
  • Legacy Challenge
  • Usability Challenge

 

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

object-oriented programming | architecture

interface vs abstract class(.net languages)

by iatanasov 1. June 2007 16:26

When should you use an abstract class, when an interface, when both? Interfaces and abstract classes seem superficially to provide almost the same capability. How do you decide which to use?

When To Use Interfaces

An interface allows somebody to start from scratch to implement your interface or implement your interface in some other code whose original or primary

purpose was quite different from your interface. To them, your interface is only incidental, something that have to add on to the their code to be able to use your package.

When To Use Abstract classes

An abstract class, in contrast, provides more structure. It usually defines some default implementations and provides some tools useful for a full implementation.

The catch is, code using it must use your class as the base. That may be highly inconvenient if the other programmers wanting to use your package have already developed their own class hierarchy independently. In Java, a class can inherit from only one base class.

When to Use Both

You can offer the best of both worlds, an interface and an abstract class. Implementors can ignore your abstract class if they choose.

The only drawback of doing that is calling methods via their interface name is slightly slower than calling them via their abstract class name.

Summary

 

Interfaces vs Abstract Classes
feature interface abstract class
multiple inheritance A class may implement several interfaces. A class may extend only one abstract class.
default implementation An interface cannot provide any code at all, much less default code. An abstract class can provide complete code, default code, and/or just stubs that have to be overridden.
constants Static final constants only, can use them without qualification in classes that implement the interface. On the other paw, these unqualified names pollute the namespace. You can use them and it is not obvious where they are coming from since the qualification is optional. Both instance and static constants are possible. Both static and instance intialiser code are also possible to compute the constants.
third party convenience An interface implementation may be added to any existing third party class. A third party class must be rewritten to extend only from the abstract class.
is-a vs -able or can-do Interfaces are often used to describe the peripheral abilities of a class, not its central identity, e.g. an Automobile class might implement the Recyclable interface, which could apply to many otherwise totally unrelated objects. An abstract class defines the core identity of its descendants. If you defined a Dog abstract class then Damamation descendants are Dogs, they are not merely dogable. Implemented interfaces enumerate the general things a class can do, not the things a class is.

In a Java context, users should typically implement the Runnable interface rather than extending Thread, because they're not really interested in providing some new Thread functionality, they normally just want some code to have the capability of running independently. They want to create something that can be run in a thread, not a new kind of thread.The similar is-a vs has-a debate comes up when you decide to inherit or delegate.

multiple inheritance for further discussion of is-a vs has-a
plug-in You can write a new replacement module for an interface that contains not one stick of code in common with the existing implementations. When you implement the inteface, you start from scratch without any default implementation. You have to obtain your tools from other classes; nothing comes with the interface other than a few constants. This gives you freedom to implement a radically different internal design. You must use the abstract class as-is for the code base, with all its attendant baggage, good or bad. The abstract class author has imposed structure on you. Depending on the cleverness of the author of the abstract class, this may be good or bad.
homogeneity If all the various implementaions share is the method signatures, then an interface works best. If the various implementations are all of a kind and share a common status and behaviour, usually an abstract class works best. Another issue that's important is what I call "heterogeneous vs. homogeneous." If implementors/subclasses are homogeneous, tend towards an abstract base class. If they are heterogeneous, use an interface. (Now all I have to do is come up with a good definition of hetero/homo-geneous in this context.) If the various objects are all of-a-kind, and share a common state and behavior, then tend towards a common base class. If all they share is a set of method signatures, then tend towards an interface.
maintenance If your client code talks only in terms of an interface, you can easily change the concrete implementation behind it, using a factory method. Just like an interface, if your client code talks only in terms of an abstract class, you can easily change the concrete implementation behind it, using a factory method.
speed Slow, requires extra indirection to find the corresponding method in the actual class. Modern JVMs are discovering ways to reduce this speed penalty. Fast
terseness The constant declarations in an interface are all presumed public static final, so you may leave that part out. You can't call any methods to compute the initial values of your constants. You need not declare individual methods of an interface abstract. They are all presumed so. You can put shared code into an abstract class, where you cannot into an interface. If interfaces want to share code, you will have to write other bubblegum to arrange that. You may use methods to compute the initial values of your constants and variables, both instance and static. You must declare all the individual methods of an abstract class abstract.
adding functionality If you add a new method to an interface, you must track down all implementations of that interface in the universe and provide them with a concrete implementation of that method. If you add a new method to an abstract class, you have the option of providing a default implementation of it. Then all existing code will continue to work without change.

 

Currently rated 4.0 by 2 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , ,

object-oriented programming

Inheritance and abstraction

by iatanasov 15. May 2007 13:20

Inheritance and abstraction are also very important features of object-oriented languages. They provide a way to make polymorphic representations of objects and object relationships that can be managed at run time or compile time.

 

Inheritance is the ability of one object to be derived by creating a new class instance from a parent or base class and overloading the constructor(s), methods, and attributes of that parent object and implementing them in the instance. In Java this is known as subclassing. Inheritance is important because many times an object contains some base functionality that another object also needs and, instead of maintaining the same logic in two objects, they can share and even override or change this functionality by using a base or parent class. If this occurs, then the base or parent object should be defined in such a way that several common derived objects can use the same common functionality from the parent. The parent should only contain functionality common to all its children.

Abstraction is the actual method in which we use inheritance. Abstraction is the ability to abstract into a base class some common functionality or design that is common to several implementation or instanced classes. The difference between implementation and abstract classes is that abstractions of classes cannot be instanced, while implementations can. Abstraction and inheritance are both aspects of polymorphism, and the reverse is true as well.


Another important aspect of object-oriented languages is how they deal with collections of objects. The equals implementation for objects is an important aspect of dealing with objects inside a collection. Languages like C#, VB.NET, and Java all use this method to help index and compare objects in collections. Let’s talk about this briefly. When a hash table or other collection object indexes and compares an object, it uses the GetHashCode() method to help in this indexing and comparison. This method can be overridden to capture a more accurate sampling of the intrinsic properties or state of the object. In other words, the GetHashCode() method can return an integer representation of the concatenated state of the properties within an object. If not overridden, then this relationship is less exact. This is important when making comparisons between objects in collection classes like iterators or generic collection objects like hash tables. You need to make accurate representations of the internal state of objects so the correct object can be compared or indexed in a collection.

There are general rules to guarantee that each object gets a

unique hashing algorithm: Objects that compare as equal must return the same hashed value. GetHashCode() must return the same value every time, unless the internal value or state is modified. The hashed value is not like a GUID (global unique identifier) in that it is not globally unique, but only unique if the hashed algorithm and the object’s value are not the same as any other object in the scope of the executing code.

The default implementation of GetHashCode() in objects that contain state variables or values is not guaranteed to be unique. That is why if uniqueness is desired, then a proper algorithm needs to be implemented in the overridden method on a particular class. To provide a complete representation of state, the values of each variable that represents the object’s state need to be part of the hashing algorithm. To illustrate the proper way to implement the GetHashCode() method, take a look at this example:


public override int GetHashCode()

{

return _name.GetHashCode() ^ _address.GetHashCode();

}


We see that the method has been overridden, and two instance variables have been concatenated with the ^ symbol and returned as their sum. Another way to do this is with the + sign, which returns the same result:


public override int GetHashCode()

{

return _name.GetHashCode() + _address.GetHashCode();

}



Taking all the variables that may change the state of the object and returning their concatenated hashed values guarantees that each object will have unique values based on state. This allows objects used as keys in collections like hash tables to act in the proper manner. The Equals(object obj) method is the required method for bitwise comparisons of value objects. It is especially useful in sorting collections or when a comparison operation is desired in a collection. Not all primitive or object types can have bitwise equality, and so those are compared by value, as in the case of decimal 2.2000 and 2.2, which have the same value but different binary equality. The proper operational sequence usually starts with a null check, then a class type comparison, and then a comparison of all the value types (or reference types) that influence the state of the class:


public override bool Equals(object obj)

{

if(obj != null && obj is Component)

return _name.Equals(((Component)obj).Name) &&

_address.Equals(((Component)obj).Address);

else

return false;

}



There are some basic rules when testing the equals implementation for proper return values:

obj1.Equals(obj1) = true — an object always

equals itself.

obj1.Equals(obj2) = obj2.Equals(obj1) —

equals implementations across different class instances

always return true on both classes if equal.

obj1.Equals(obj2) && obj2.Equals(obj3) && obj3.Equals(obj1) = true — if object 1 is

equal to object 2 and object 2 is equal to object 3, then

object 3 must be equal to object 1.

All calls to Equals() return the same value unless the class’s state or internal value is modified.

Equals(null) always returns false.


 

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , ,

object-oriented programming

Powered by BlogEngine.NET 1.1.0.7
Theme by Mads Kristensen

About the author

Ivan Atanasov - web developer
E-mail me Send mail Subscribe Feed

Calendar

<<  July 2008  >>
MoTuWeThFrSaSu
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

View posts in large calendar

Pages

    Recent posts

    Recent comments

    Authors

    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

    © Copyright 2008 it-coder.com

    Sign in