WORM gets my vote, I have been using it for just over 6 months now and have used it in 2 major projects and a few minor, personal ones. I agree with the KISS methodology, especially since most of the applications I write
really don't need to be all that crazy. I use CodeSmith templates (provided when you buy the WORM) that I have modified for my own use to provide the DTOs and a light wrapper around the WORM (to make swapping WORM out easier, if I ever need to do that).
Combined, I can get things up and running quickly once I have the database designed and what not (currently we simply map tables to objects 1:1, although WORM does support mapping to views as well!).
I have not used NHibernate; so, I cannot comment on it. I have used several MDA tools (such as MIA), but WilsonORMapper is my current top pick.
We are using WilsonORMapper on our current enterprise project. We have a team of 4 developers. The database infrastructure is ~200 tables.
In short, WilsonORMapper works great.
We are using the WilsonORMapper to do virtually everything. We are not using stored procedures, except in some rare cases. (Though WilsonORMapper does support them.) The result, so far, has been nothing short of beautiful. The learning curve is quite flat and
one can get "up and running" fast. We are generating classes using the included WilsonORHelper; but, there are CodeSmith templates for more control-- control which we have not needed. There is a lot of sample code and direct support at
http://www.wilsondotnet.com/ with great feedback and helps from Paul Wilson himself. And so on.
From an ease-of-adoption and product-cost perspective, one cannot lose with WilsonORMapper.
I recommed it WilsonORMapper highly.
By the way, I also like code generation and have used CodeSmith and MyGeneration, both of which are excellent products. However, they are not, in themselves, ORMappers and, so far, I have found that WilsonORMapper gets more done out-of-the-box than pure code-generation.
This is, of course, a stylistic preference, that can vary from developer to developer.
Finally, I want to comment generally on something that I have discovered about ORMapping. In order to use it in a "pain free", one must think like an ORMapper. That is, there is a stylistic change that needs to take place in order to use ORMapping successfully.
There are considerations and, yes, concessions that one address. This is obvious by the simple fact that when one codes by hand, one can write anything-- but, when one uses a tool, then one is bound by that tool's assumptions. At the current state of technology,
ORMappers cannot "do everything one can do by hand". I am convinced of that. Some are very good and quite complete; but, if one looks hard enough there will be some strange object-graph, some odd inheritance-chain, some deviant database, or other such construct
that ORMapper N cannot handle. However, a good ORMapper, such as WilsonORMapper, can do 95% (or more) of the grunt CRUD work in a standard business application. However, such tools do things a certain way and if a developer is not willing to bend a bit and
give in to the "style" of the ORMapper, then there will be cursing at the sqare-peg and the round-hole. If however, one adheres to simple, generic maxims such as "good code is working code" and "good code uses the basic principles of OOP" and "good code is
easy to maintain", then one is a lot better off.
Finally, I want to comment generally on something that I have discovered about ORMapping. In order to use it in a "pain free", one must think like an ORMapper. That is, there is a stylistic change that needs to take place in order to use ORMapping successfully.
There are considerations and, yes, concessions that one address. This is obvious by the simple fact that when one codes by hand, one can write anything-- but, when one uses a tool, then one is bound by that tool's assumptions.
One that's helpful to point out is that there are many different mappers out there that all have different assumptions. Some favor starting with the database, some favor starting with the object model, some favor "pure objects", and others favor "entity
objects". Frans has an excellent blog about the different views of the data access problem. I think an important step in choosing a mapper is to realize how you (and your team) like to work and choosing a mapper that fits that "style". Picking the mapper that
is most similiar to your thinking can greatly lessen your learning curve and lead to fewer "concessions".
Those are both really great comments. So far, WORM sounds like the easiest, most flexible thing to use, and I like that i can get the source code.
I come from a more or less OOP behaviorist/purist background, but also a firm believer in a higly normalized (3-5nf) database. I don't want concessions mucking up my data, I don't want concessions making me completely non-oop. Hans' product is very robust,
but as I said it has a few ugly flaws like the null object scenario. I also prefer my objects to act like objects and not like "entities". Thats why mapping appeals to me more than code generation...besides we can use codesmith for generation if need be.
Of course that's just me. I'm not sure what my boss or the other developers would prefer.
BTW, how does WORM (or any others) handle many-to-many relationships, terniary relationships (a table with just 3 foreign keys representing a 3 way relationship) and so on? Do you have the choice on whether a removal from a collection deletes the object, or
merely deletes the relationship?
Those are both really great comments. So far, WORM sounds like the easiest, most flexible thing to use, and I like that i can get the source code.
I come from a more or less OOP behaviorist/purist background, but also a firm believer in a higly normalized (3-5nf) database. I don't want concessions mucking up my data, I don't want concessions making me completely non-oop. Hans' product is very robust,
but as I said it has a few ugly flaws like the null object scenario. I also prefer my objects to act like objects and not like "entities". Thats why mapping appeals to me more than code generation...besides we can use codesmith for generation if need be.
Of course that's just me. I'm not sure what my boss or the other developers would prefer.
BTW, how does WORM (or any others) handle many-to-many relationships, terniary relationships (a table with just 3 foreign keys representing a 3 way relationship) and so on? Do you have the choice on whether a removal from a collection deletes the object, or
merely deletes the relationship?
Craig
WORM is excellent at letting you firstly design the DB as a DB should be designed, then apply the mappings to the Bll, which is how a mapper should work. However, purely for Bll coding puposes, I have found that it is often easier to specify a single unique
ID column to all of my DB tables including ones that have composite keys. This allows for the integrity of the DB to be retained while making coding easier as each object just has a single OID.
It handles m..n just fine. It allows you to define m..n, m..1, 1..m relationships in the mappings, however, I have not yet had any need to define a ternary relationship, so I can't help you here. It also allows you to specify cascade deletes so that child objects
are deleted upon the deletion of an object. And, if I understand you correctly, I don''t think that it will delete an object on removal from a collection (wouldn't this be a design flaw in the mapper? What if that object is used elsewhere?)
I think someone else already answered most of this with (pretty much) the same answer that I would have given. Regardless, I may prattle a bit.
Regarding keys, I generally use artificial, auto-generated, single-column, primary keys. As such, I have not encountered compound keys often. Maybe WilsonORMapper does support compund-keys; but, I have not looked into it much at all. You are referring to "terniary
relationships" and I can say for certain that I do have tables with 3 foreign keys in them and they work fine with the WilsonORMapper.
Regarding deletion, it looks to me like cascade delete is either on or off for a given entity. This is set in a XML mapping file that describes the object relations. If cascade delete is on, it does, in fact, cascade delete (even if SQL Server has cascade delete
turned off); foreign key links are managed and rows delete without any constraint violations, even in a highly normalized database. If cascade delete is off, then deletion stops at the current object and if constraints exist the standard error SQL error is
thrown.
In general, I will note that there is a list at
http://www.ormapper.net/ which provides a quick overview of the WilsonORMapper.
BTW, there are a few more points that I should have mentioned. These are things that are important to me; but, I think that they hold value globally.
--The WilsonORMapper has an active development process.
By this I mean that, it should be noted that while WilsonORMapper is not an Open Source Project (uppercase) it is, in a very real sense, and open source project (lowercase). That is, Paul Wilson has had a good deal of review, collaboration, helps, and hints
from those who use the product. This is clearly evident in his attributions.
--WilsonORMapper is a mature and stable product.
The current release as of now is V4.0. Each release has brought constant improvement and stabilization. Paul Wilson is very responsive to bug reports and suggestions at his forums.
--WilsonORMapper is designed with the future of DotNet in mind.
The WilsonORMapper is designed with the (upcoming?) release of Microsoft's OR mapping capabilities for DotNet. The syntax and usage is quite similar in many areas. Therefore, one will never be far afield from the mainstream MS way of doing things, just in case.
Of course, the WilsonORMapper already supports databases other than just SQL Server; so, it is already at least a step ahead.
BTW-- For the record, please note that I am not in any way affiliated with Paul Wilson. I paid in full for my subscription. However, I do believe that it is some of the best money I have spent on software.
About the terniary database relations, these are the persistence mechanism for association classes. Once this is understood, it is much easier to map it to a new object model.
Thanks,
Udi Dahan - The Software Simplist
Enterprise Development Expert & SOA Specialist
My company is currently evaluating O/R Mappers (again.) The two that interest me the most are NHibernate and Paul Wilson's. Paul, I know what your vote will be so you don't count. :)
We're currently using CSLA with custom codesmith templates but it is pretty slow going and error prone. There's a LOT I don't like about CSLA. We have recently looked at IdeaBlade but it does NOT support identity columns which is a problem for existing databases
and very non-intuitive at the DB level. Also there is no inheritance or collection support. Another one we've used on a project is LLBLGen Pro. LLBLGen was ok until we found a bug where if you access a property, and the record represented by the property
does not exist in the database, LLBLGen instantiates a new object for you in the object model. However, when you go to save, it actually tries to save this new, "Blank" object as a record, which then throws a very obscure error later on. This happens constantly
with LLBLGen and is really annoying.
You can switch that off for a long time already (so it produces null instead of a new entity). It only happens in lazy loading scenario's and the new entity is produced for backwards compatibility as the first versions had that feature.
Furthermore, if you run into this, your code relies on data it doesn't check: you request related entities from the db which aren't there, but don't check what's returned. If you'd do that, you wouldn't have a problem.
LLBLGen actually did do a lot for you, however it was complicated to use, did not store the mappings in a XML or otherwise human readable file (which made comparison in source control impossible as well as copying
and pasting mappings from one file to another impossible)
Having mappings in an xml file isn't very 'version' friendly either. If you have 10 revisions of the mapping file, and you have a large system, chances are you're in trouble too if you want to copy/paste mappings over, as that's a lot of xml to wade through.
and did not support inheritance.
coming soon, is in development :)
Finally, we are also looking at NetTiers, which is a codesmith template. However, the newest version uses Enterprise Library, which throws xcopy deployment out the window. It also does not support inheritance straight out the box although you can modify the
templates mabye.
So in summary, we're looking for an O/R Mapper that supports the following:
-Inheritance (Amazing how many do not do this!)
Well, you often need a decorator more than an inherited type. A lot of inheritance trees aren't really hierarchies of very different types, but just behavior changes, something which you can do with all mappers today. Real type inheritance as in: employee -
manager - boardmember and boardmember then has a relation with companycar, is not that common, as it also shows problems when you want to semantically promote an entity (i.e. its data) to another type, for example make a manager a boardmember in the example
above. You then are better of with a decorator pattern implementation than with an inheritance tree.
It's useful, but can bite you as well. The beauty is that you can write very great software without entity hierarchies.
-XML mapping/configuration file
You will be bitten by this. A serialized object model is very easy to use for example: you can write a few lines of code to load your .lgp file into memory and manipulate it with simple code :)
Lead developer of LLBLGen Pro, the productive O/R mapper for .NET
LLBLGen Pro website: http://www.llblgen.com My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
You can switch that off for a long time already (so it produces null instead of a new entity). It only happens in lazy loading scenario's and the new entity is produced for backwards compatibility as the first versions had that feature.
Furthermore, if you run into this, your code relies on data it doesn't check: you request related entities from the db which aren't there, but don't check what's returned. If you'd do that, you wouldn't have a problem.
Frans, I realize that you are defending your product, so I please understand if I don't consider you entirely objective. And I'm very glad that you have fixed the problem. However at the time that i used the product, it was really a sore point with me.
It was so uncharacteristic of how the .NET framework works. In .NET, as well as most programming languages, if you attempt to get the 3rd item out of a recordset, and there are only 2 records, you get an immediate error. If you attempt to reference a property
in a null object, you get an error. If you attempt to get a field out of an IDataReader that isn't there, you get an error. The framework NEVER instantiates something for you automatically. Your product did. But there was no way to know it was doing
that, until later on when you tried to save, at which point it finally thru an exception. NOT an exception about the null object, but about a bad query (because it was creating an insert statement with no columns if I remember.) This was just abysmal. Debugging
this requred you to trace through all your steps in the object graph, all the way into complex machinations in the generated code, to finally see which new, empty entity was getting instantiated and was generating the bad query. Ug.
There is a saying in Taoism that I think applies to many aspects of life, including programming: "Meet problems early." Your product, by instantiating the null object without telling the developer, put the problem off until much later in the lifecycle (potentially
several postbacks or even several pages later in an ASP.NET app) and therefore much more difficult to deal with. I do agree that you are going to have to check sometimes for null or empty data. Every object developer and every O/R Mapper has to deal with
the problem of nulls. However, the fact is that all of us will make mistakes and try to reference things that aren't there whether they are records, collection items or individual objects. Who among us has not gotten the ubiquitous "Object reference not set
to an instance of an object" error? :) All of us sometimes forget to check for nulls on an object or chunk of data. The way your product dealt with nulls actually obfuscated mistakes like these and made a relatively simple exception (null reference) into
something much more difficult to track down later on. Worse, some of these errors made it into production whereas if your product had immediately given the "object reference" exception, much head scratching would have been avoided.
I don't know if you remember, but you and I had emailed each other back and forth quite a bit about this issue. At the time, my perception was that you didn't seem very concerned about the issue. I'm pleased that you have made it a priority and understand
that you have to have leave the "lazy instatiating" as an option for backwards compatiibility.
FransBouma
Having mappings in an xml file isn't very 'version' friendly either. If you have 10 revisions of the mapping file, and you have a large system, chances are you're in trouble too if you want to copy/paste mappings over, as that's a lot of xml to wade through.
I completely disagree. When using your product, we had a contractor working offsite and out of state. That contractor was often disconnected from our VPN and therefore from our source control (VSS). Occasionally, she would have to make changes to the data
structure and therefore the LLBLGen project file and generated code. When she checked back in, there were times that I already had made change to the data structure and mappings as well. Merging the changes was a chore that ranged from painful to nearly
impossible. The project file/mapping was in a binary format, so no merge/diff tool could sync up the differences. We couldn't even "eyeball it" and copy individual changes from one person's version of the file to the other, because of the proprietary format.
So each time we got out of sync, one of us would have to get on the phone with the other, go in to the GUI and manually add the changes thru point and click and hope we got them exactly right. I agree that 10 versions of the a large mapping could be problematic,
but we only had 2 versions we were trying mess with. Are you really going to suggest to me that XML, which is human readable and can be synched using a merge tool, isn't going to be far, far easier to fix problems like this than your proprietary binary format?
FransBouma
Well, you often need a decorator more than an inherited type. A lot of inheritance trees aren't really hierarchies of very different types, but just behavior changes, something which you can do with all mappers today. Real type inheritance as in: employee -
manager - boardmember and boardmember then has a relation with companycar, is not that common, as it also shows problems when you want to semantically promote an entity (i.e. its data) to another type, for example make a manager a boardmember in the example
above. You then are better of with a decorator pattern implementation than with an inheritance tree.
It's useful, but can bite you as well. The beauty is that you can write very great software without entity hierarchies.
I agree that real inheritance is rare. Inheritance is NOT the silver bullet of code reuse that some beginners to the OOP paradigm seem to think it is. However, when a true inheritance hierarchy presents itself, using a decorator pattern or delegation or something
tends to be rather ugly in my experience. A bit like trying to squeeze a square peg into a round hole. Its a matter of using the the right tool for the right job: use inheritance when you see an "is a" or "is a type of" relationship and composition or aggregation
when there is a "has a" relationship. The latter is more common; the former is still very useful at times.
-XML mapping/configuration file
FransBouma
You will be bitten by this. A serialized object model is very easy to use for example: you can write a few lines of code to load your .lgp file into memory and manipulate it with simple code :)
Possibly. But I doubt I will be bitten as bad as I was with your .lgp file. I wasn't aware that you could maniuplate the project file as an object, or maybe that wasn't in the feature set at the time that we used it. That would have been easier for us to
synch up differences, although I doubt as easy as copying and pasting a few lines of XML. And couldn't your project file's object model could just as easily be serialzed down to xml, that way you could alter it programatically the way you mentioned by manipulating
the object model, OR alter it using notepad the way i mentioned? Best of both worlds?
Let me also say that lots of O/R Mappers use and XML configuration file or XML serialization of the "mapping objects" the way I describe. NHibernate, WORM and IdeaBlade are just a few. There must be something to that whole "easy to read, easy to parse."
Frans, I am sorry if this post and my original post seem a little harsh. The fact was, we were your customers and our experience with your product was not very positive. I emailed you for help and I give you credit for being very prompt in getting back to
us. However, you didn't seem to interested in what I and other developers saw as some major, logical flaws in your product. That being said, there were LOTS of things i really liked about LLBLGen: strongly typed object queries, collection generation, the
inheritance hierarchy it created for regens, the GUI was great, support for relationships that were NOT in the database as contraints or RI, and so on. And it looks like you are getting some of the major blemishes the product cleaned up.
JasonBunting
Member
525 Points
105 Posts
Re: WORM, NHibernate and reviews of any other ORMappers
Jul 20, 2005 11:37 PM|LINK
Get the WORM.
mkamoski
Contributor
5694 Points
1565 Posts
Re: WORM, NHibernate and reviews of any other ORMappers
Jul 21, 2005 06:02 PM|LINK
Fregas--
I have not used NHibernate; so, I cannot comment on it. I have used several MDA tools (such as MIA), but WilsonORMapper is my current top pick.
We are using WilsonORMapper on our current enterprise project. We have a team of 4 developers. The database infrastructure is ~200 tables.
In short, WilsonORMapper works great.
We are using the WilsonORMapper to do virtually everything. We are not using stored procedures, except in some rare cases. (Though WilsonORMapper does support them.) The result, so far, has been nothing short of beautiful. The learning curve is quite flat and one can get "up and running" fast. We are generating classes using the included WilsonORHelper; but, there are CodeSmith templates for more control-- control which we have not needed. There is a lot of sample code and direct support at http://www.wilsondotnet.com/ with great feedback and helps from Paul Wilson himself. And so on.
From an ease-of-adoption and product-cost perspective, one cannot lose with WilsonORMapper.
I recommed it WilsonORMapper highly.
By the way, I also like code generation and have used CodeSmith and MyGeneration, both of which are excellent products. However, they are not, in themselves, ORMappers and, so far, I have found that WilsonORMapper gets more done out-of-the-box than pure code-generation. This is, of course, a stylistic preference, that can vary from developer to developer.
Finally, I want to comment generally on something that I have discovered about ORMapping. In order to use it in a "pain free", one must think like an ORMapper. That is, there is a stylistic change that needs to take place in order to use ORMapping successfully. There are considerations and, yes, concessions that one address. This is obvious by the simple fact that when one codes by hand, one can write anything-- but, when one uses a tool, then one is bound by that tool's assumptions. At the current state of technology, ORMappers cannot "do everything one can do by hand". I am convinced of that. Some are very good and quite complete; but, if one looks hard enough there will be some strange object-graph, some odd inheritance-chain, some deviant database, or other such construct that ORMapper N cannot handle. However, a good ORMapper, such as WilsonORMapper, can do 95% (or more) of the grunt CRUD work in a standard business application. However, such tools do things a certain way and if a developer is not willing to bend a bit and give in to the "style" of the ORMapper, then there will be cursing at the sqare-peg and the round-hole. If however, one adheres to simple, generic maxims such as "good code is working code" and "good code uses the basic principles of OOP" and "good code is easy to maintain", then one is a lot better off.
HTH.
--Mark Kamoski
rsmoke21
Contributor
3931 Points
792 Posts
Re: WORM, NHibernate and reviews of any other ORMappers
Jul 21, 2005 06:36 PM|LINK
One that's helpful to point out is that there are many different mappers out there that all have different assumptions. Some favor starting with the database, some favor starting with the object model, some favor "pure objects", and others favor "entity objects". Frans has an excellent blog about the different views of the data access problem. I think an important step in choosing a mapper is to realize how you (and your team) like to work and choosing a mapper that fits that "style". Picking the mapper that is most similiar to your thinking can greatly lessen your learning curve and lead to fewer "concessions".
fregas
Member
406 Points
96 Posts
Re: WORM, NHibernate and reviews of any other ORMappers
Jul 21, 2005 07:13 PM|LINK
Those are both really great comments. So far, WORM sounds like the easiest, most flexible thing to use, and I like that i can get the source code.
I come from a more or less OOP behaviorist/purist background, but also a firm believer in a higly normalized (3-5nf) database. I don't want concessions mucking up my data, I don't want concessions making me completely non-oop. Hans' product is very robust, but as I said it has a few ugly flaws like the null object scenario. I also prefer my objects to act like objects and not like "entities". Thats why mapping appeals to me more than code generation...besides we can use codesmith for generation if need be.
Of course that's just me. I'm not sure what my boss or the other developers would prefer.
BTW, how does WORM (or any others) handle many-to-many relationships, terniary relationships (a table with just 3 foreign keys representing a 3 way relationship) and so on? Do you have the choice on whether a removal from a collection deletes the object, or merely deletes the relationship?
Craig
rsmoke21
Contributor
3931 Points
792 Posts
Re: WORM, NHibernate and reviews of any other ORMappers
Jul 21, 2005 07:59 PM|LINK
sroughley
Participant
1404 Points
381 Posts
Re: WORM, NHibernate and reviews of any other ORMappers
Jul 22, 2005 08:33 AM|LINK
WORM is excellent at letting you firstly design the DB as a DB should be designed, then apply the mappings to the Bll, which is how a mapper should work. However, purely for Bll coding puposes, I have found that it is often easier to specify a single unique ID column to all of my DB tables including ones that have composite keys. This allows for the integrity of the DB to be retained while making coding easier as each object just has a single OID.
It handles m..n just fine. It allows you to define m..n, m..1, 1..m relationships in the mappings, however, I have not yet had any need to define a ternary relationship, so I can't help you here. It also allows you to specify cascade deletes so that child objects are deleted upon the deletion of an object. And, if I understand you correctly, I don''t think that it will delete an object on removal from a collection (wouldn't this be a design flaw in the mapper? What if that object is used elsewhere?)
Stephen.
mkamoski
Contributor
5694 Points
1565 Posts
Re: WORM, NHibernate and reviews of any other ORMappers
Jul 22, 2005 01:51 PM|LINK
I think someone else already answered most of this with (pretty much) the same answer that I would have given. Regardless, I may prattle a bit.
Regarding keys, I generally use artificial, auto-generated, single-column, primary keys. As such, I have not encountered compound keys often. Maybe WilsonORMapper does support compund-keys; but, I have not looked into it much at all. You are referring to "terniary relationships" and I can say for certain that I do have tables with 3 foreign keys in them and they work fine with the WilsonORMapper.
Regarding deletion, it looks to me like cascade delete is either on or off for a given entity. This is set in a XML mapping file that describes the object relations. If cascade delete is on, it does, in fact, cascade delete (even if SQL Server has cascade delete turned off); foreign key links are managed and rows delete without any constraint violations, even in a highly normalized database. If cascade delete is off, then deletion stops at the current object and if constraints exist the standard error SQL error is thrown.
In general, I will note that there is a list at http://www.ormapper.net/ which provides a quick overview of the WilsonORMapper.
BTW, there are a few more points that I should have mentioned. These are things that are important to me; but, I think that they hold value globally.
--The WilsonORMapper has an active development process.
By this I mean that, it should be noted that while WilsonORMapper is not an Open Source Project (uppercase) it is, in a very real sense, and open source project (lowercase). That is, Paul Wilson has had a good deal of review, collaboration, helps, and hints from those who use the product. This is clearly evident in his attributions.
--WilsonORMapper is a mature and stable product.
The current release as of now is V4.0. Each release has brought constant improvement and stabilization. Paul Wilson is very responsive to bug reports and suggestions at his forums.
--WilsonORMapper is designed with the future of DotNet in mind.
The WilsonORMapper is designed with the (upcoming?) release of Microsoft's OR mapping capabilities for DotNet. The syntax and usage is quite similar in many areas. Therefore, one will never be far afield from the mainstream MS way of doing things, just in case. Of course, the WilsonORMapper already supports databases other than just SQL Server; so, it is already at least a step ahead.
BTW-- For the record, please note that I am not in any way affiliated with Paul Wilson. I paid in full for my subscription. However, I do believe that it is some of the best money I have spent on software.
HTH.
Thank you.
--Mark Kamoski
UdiDahan
Member
114 Points
22 Posts
Re: WORM, NHibernate and reviews of any other ORMappers
Jul 22, 2005 04:51 PM|LINK
Udi Dahan - The Software Simplist
Enterprise Development Expert & SOA Specialist
FransBouma
Participant
1509 Points
312 Posts
Re: WORM, NHibernate and reviews of any other ORMappers
Jul 23, 2005 01:21 PM|LINK
You can switch that off for a long time already (so it produces null instead of a new entity). It only happens in lazy loading scenario's and the new entity is produced for backwards compatibility as the first versions had that feature.
Furthermore, if you run into this, your code relies on data it doesn't check: you request related entities from the db which aren't there, but don't check what's returned. If you'd do that, you wouldn't have a problem.
Having mappings in an xml file isn't very 'version' friendly either. If you have 10 revisions of the mapping file, and you have a large system, chances are you're in trouble too if you want to copy/paste mappings over, as that's a lot of xml to wade through.
coming soon, is in development :)
Well, you often need a decorator more than an inherited type. A lot of inheritance trees aren't really hierarchies of very different types, but just behavior changes, something which you can do with all mappers today. Real type inheritance as in: employee - manager - boardmember and boardmember then has a relation with companycar, is not that common, as it also shows problems when you want to semantically promote an entity (i.e. its data) to another type, for example make a manager a boardmember in the example above. You then are better of with a decorator pattern implementation than with an inheritance tree.
It's useful, but can bite you as well. The beauty is that you can write very great software without entity hierarchies.
You will be bitten by this. A serialized object model is very easy to use for example: you can write a few lines of code to load your .lgp file into memory and manipulate it with simple code :)
LLBLGen Pro website: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
fregas
Member
406 Points
96 Posts
Re: WORM, NHibernate and reviews of any other ORMappers
Jul 23, 2005 07:03 PM|LINK
Frans, I realize that you are defending your product, so I please understand if I don't consider you entirely objective. And I'm very glad that you have fixed the problem. However at the time that i used the product, it was really a sore point with me. It was so uncharacteristic of how the .NET framework works. In .NET, as well as most programming languages, if you attempt to get the 3rd item out of a recordset, and there are only 2 records, you get an immediate error. If you attempt to reference a property in a null object, you get an error. If you attempt to get a field out of an IDataReader that isn't there, you get an error. The framework NEVER instantiates something for you automatically. Your product did. But there was no way to know it was doing that, until later on when you tried to save, at which point it finally thru an exception. NOT an exception about the null object, but about a bad query (because it was creating an insert statement with no columns if I remember.) This was just abysmal. Debugging this requred you to trace through all your steps in the object graph, all the way into complex machinations in the generated code, to finally see which new, empty entity was getting instantiated and was generating the bad query. Ug.
There is a saying in Taoism that I think applies to many aspects of life, including programming: "Meet problems early." Your product, by instantiating the null object without telling the developer, put the problem off until much later in the lifecycle (potentially several postbacks or even several pages later in an ASP.NET app) and therefore much more difficult to deal with. I do agree that you are going to have to check sometimes for null or empty data. Every object developer and every O/R Mapper has to deal with the problem of nulls. However, the fact is that all of us will make mistakes and try to reference things that aren't there whether they are records, collection items or individual objects. Who among us has not gotten the ubiquitous "Object reference not set to an instance of an object" error? :) All of us sometimes forget to check for nulls on an object or chunk of data. The way your product dealt with nulls actually obfuscated mistakes like these and made a relatively simple exception (null reference) into something much more difficult to track down later on. Worse, some of these errors made it into production whereas if your product had immediately given the "object reference" exception, much head scratching would have been avoided.
I don't know if you remember, but you and I had emailed each other back and forth quite a bit about this issue. At the time, my perception was that you didn't seem very concerned about the issue. I'm pleased that you have made it a priority and understand that you have to have leave the "lazy instatiating" as an option for backwards compatiibility.
I completely disagree. When using your product, we had a contractor working offsite and out of state. That contractor was often disconnected from our VPN and therefore from our source control (VSS). Occasionally, she would have to make changes to the data structure and therefore the LLBLGen project file and generated code. When she checked back in, there were times that I already had made change to the data structure and mappings as well. Merging the changes was a chore that ranged from painful to nearly impossible. The project file/mapping was in a binary format, so no merge/diff tool could sync up the differences. We couldn't even "eyeball it" and copy individual changes from one person's version of the file to the other, because of the proprietary format. So each time we got out of sync, one of us would have to get on the phone with the other, go in to the GUI and manually add the changes thru point and click and hope we got them exactly right. I agree that 10 versions of the a large mapping could be problematic, but we only had 2 versions we were trying mess with. Are you really going to suggest to me that XML, which is human readable and can be synched using a merge tool, isn't going to be far, far easier to fix problems like this than your proprietary binary format?
I agree that real inheritance is rare. Inheritance is NOT the silver bullet of code reuse that some beginners to the OOP paradigm seem to think it is. However, when a true inheritance hierarchy presents itself, using a decorator pattern or delegation or something tends to be rather ugly in my experience. A bit like trying to squeeze a square peg into a round hole. Its a matter of using the the right tool for the right job: use inheritance when you see an "is a" or "is a type of" relationship and composition or aggregation when there is a "has a" relationship. The latter is more common; the former is still very useful at times.
Possibly. But I doubt I will be bitten as bad as I was with your .lgp file. I wasn't aware that you could maniuplate the project file as an object, or maybe that wasn't in the feature set at the time that we used it. That would have been easier for us to synch up differences, although I doubt as easy as copying and pasting a few lines of XML. And couldn't your project file's object model could just as easily be serialzed down to xml, that way you could alter it programatically the way you mentioned by manipulating the object model, OR alter it using notepad the way i mentioned? Best of both worlds?
Let me also say that lots of O/R Mappers use and XML configuration file or XML serialization of the "mapping objects" the way I describe. NHibernate, WORM and IdeaBlade are just a few. There must be something to that whole "easy to read, easy to parse."
Frans, I am sorry if this post and my original post seem a little harsh. The fact was, we were your customers and our experience with your product was not very positive. I emailed you for help and I give you credit for being very prompt in getting back to us. However, you didn't seem to interested in what I and other developers saw as some major, logical flaws in your product. That being said, there were LOTS of things i really liked about LLBLGen: strongly typed object queries, collection generation, the inheritance hierarchy it created for regens, the GUI was great, support for relationships that were NOT in the database as contraints or RI, and so on. And it looks like you are getting some of the major blemishes the product cleaned up.
Fregas