Welcome to the CodeSmith Community!

Alternative WilsonORMapper Templates

File Share

A description has not yet been added to this group.

Alternative WilsonORMapper Templates

  • rated by 0 users
  • This post has 39 Replies |
  • 9 Followers

  • For those that use Paul Wilson's O/R mapper, here are some additional templates for generating a framework around that tool. While Paul Welter provides templates for this purpose, I don't particularly care for the pattern used in his generated classes (follows the 'ActiveRecord' design pattern, AFAIK). I personally don't like having business objects that 'know' anything about the concept of persistence (saving, getting, etc.). While this is a relatively common way of doing things (I did the same thing in the past), it doesn't work for me any longer simply because of my personal opinions with regards to application architecture. Granted, 'it depends' on the application - I simply don't find myself ever needing to write one with that pattern.

    There is a readme.txt file that contains more than enough verbosity on what these do/don't do. However, here are some big ones:

    1. These have been verified to work in the following versions of CodeSmith (i.e. I have tried them in these versions, they may also work in others as well, YMMV):

         v2.6 (the 'free' version)
         v3.1.6
    2. These generate C# code.
    3. These have been used against SQL Server 2000 (theoretically, they work against any that CodeSmith and WilsonORMapper support)
    4. They target v1.1 of the .NET Framework (though they work against 2.0 as well, they simply don't support generics yet).
    5. I hope someone finds these useful. Stick out tongue [:P]

      Thanks.



      [EDIT: Go to the files section of this site to get the latest, this is a bad place to get these (unless you want the oldest ones around)]
    j a s o n   b u n t i n g
  • It would be great if you would post these to the files section of the community as well so that they are easier to find for everyone.

    Eric J. Smith
    Founder / CEO
    CodeSmith Tools, LLC

  • Eric,

    I looked at doing that before I posted, but alas I cannot find the way to post files to that section of the site. Is it that I don't have proper permissions or is it that I am so easily lost that I wouldn't find my way out of a paper bag? (maybe both) Stick out tongue [:P]

    Let me know and I will post them.

    Thanks

    j a s o n   b u n t i n g
  • Thanks Jason - these are really cool.  I definately agree with you on the manager-based  persistence (Repository) being superior to the ActiveRecord pattern for all but the simplest apps. I think this will be especially apparent when you add transaction support.  I was happy to learn that you are a fellow fan of Worm and that your architectual preferences are similar to mine, having seen your name around for a few years now.

    I have 2 questions for you to consider.

    1.  Do you think there needs to be an EntityPersistenceManager (repository) for EVERY domain entity?  Or would it make more sense to only have these managers for the aggregate-root types.  For instance, realisticly we would never need to fetch a collection of all the OrderDetail objects, only those that are part of a root Order - so we would just need a InstantiateNewOrderDetail in the OrderManager itself, and never need a GetAll method for the OrderDetail.
    2. Would it buy us anything if instead of the repositories being static classes, we use a singleton'd object with instance methods?  With instances we can use things like session-specific caching, isolated context, etc, which we lose the opportunity using all static methods.  So starting off with the singleon pattern,  if we ever decide we really NEED a new instance of a manager, we can just change the GetInstance method to return a new instance instead of the static singleton.  (Encapsulated Construction).  

    Just a couple things to think about.  I am by no means an expert in this stuff, but these are just some of the things I am wondering about.

    Regards,

    David

  • Jason,

    Sorry about the file gallery.  Looks like my permission settings were messed up.  I have changed them now so that you should see a Upload button at the top of the file listing when you are in the folder.

    Eric J. Smith
    Founder / CEO
    CodeSmith Tools, LLC

  • David -

    > Thanks Jason - these are really cool.

    Thanks, I doubt such a compliment is deserved though - you must not have looked too closely at these. Wink [;)] By the way, I have updated the templates a tiny bit since I posted that yesterday; you might want to get the latest.

    > Do you think there needs to be an EntityPersistenceManager (repository) for EVERY
    > domain entity? Or would it make more sense to only have these managers for the
    > aggregate-root types.  For instance, realisticly we would never need to fetch a
    > collection of all the OrderItem objects, only those that are part of a root Order
    > - so we would just need a InstantiateNewOrderItem in the OrderManager itself, and
    > never need a GetAll method for the OrderItem.

    I am all for making this generated framework better, and in order to do that I need feedback and to engage in an intelligent conversation about it (which would actually remove me from any such possibility); to that end, I appreciate your taking time to pose these questions. And now for the rambling that characterizes most conversations with me:

    I think I understand what you are getting at, and I like the line of reasoning but it begs some questions that also need to be examined (questions that have probably been addressed by more intelligent people than myself). For example, we could say the same goes for the relationship between Customer and Order. To illustrate one of the questions I am referring to, let me paraphrase your own words, modified for this scenario:

    ...realistically we would never need to fetch a collection of all the Order objects, only those that are part of a root Customer - so we would just need an InstantiateNewOrder in the CustomerManager itself, and never need a GetAll method for the Order.

    The question I am getting at is, what are the "aggregate-root" types? You could have an object hierarchy like Country->State->Customer->Order->OrderItem, etc. This line of questioning can go around and around, depending on how deep the object heirarchy may be. Now, this does not mean the question isn't valid, but the answer I am interested in getting is to the question about where and how we handle this idea of managing the objects, their relationships to each other, and their persistence in a way that creates and preserves semantics related to the business domain the application addresses. For example, a question that I am curious about is illustrated by this scenario:

    How do we delete an instance of the OrderItem class? Let's say I have an Order that aggregates nine OrderItems, and I want to delete one of them; what would the code that I need to write look like? Here is code that does NOT persist the changed collection (i.e. it does not delete from the data store the same one we removed from the collection):

     // let's retrieve an order
     Order previousOrder = OrderManager.GetOne(orderId);
     
     // arbitrarily, let's remove the 5th member of that collection
     OrderItem someOrderItem = previousOrder.OrderItems[5];
     previousOrder.OrderItems.Remove(someOrderItem);
     
     // second parameter tells WORM to use PersistDepth.ObjectGraph
     // when it persists the Order object
     OrderManager.Save(previousOrder, true);

    The question is, does it make sense for this to NOT work? If we really want our relational world (the data store that we are mapping to) to reflect our OO world, I would think the data store should remove this OrderItem from its association with that Order (in the above example, it doesn't necessarily mean we want to delete it from the data store, just delete the relationship - we still have the someOrderItem object hanging around, which means it is now orphaned (and would that even be possible if we have a rule that no OrderItems can exist without an order?)).

    There are so many questions, most of which, with respect to these templates and the code they produce, can be eliminated if we keep a lot of the low-level API around (I use the term "low-level" in a very relative sense - the functions of the Persistence Manager classes would be considered "low-level" in this conversation because they are relatively raw in their operations (i.e. they do basic CRUD without regard for business logic, etc.)) and force the developer to handle that each time it needs to be done. Personally I would like, as much as possible and where it makes sense, for the relational world to reflect the actions in the OO world. However, the reality is that this would greatly complicate things and doesn't always make sense.

    > Would it buy us anything if instead of the repositories being static classes, we
    > use a singleton'd object with instance methods?  With instances we can use things
    > like session-specific caching, isolated context, etc, which we lose the opportunity
    > using all static methods.  So starting off with the singleon pattern,  if we ever
    > decide we really NEED a new instance of a manager, we can just change the GetInstance
    > method to return a new instance instead of the static singleton.  (Encapsulated
    > Construction).

    Good idea, I would love to think more about this (have been meaning to think about it, actually) and see some examples of what you propose (only because I am short on time, as we all seem to be!). We get some caching capabilities with WORM, and where that happens I don't want to duplicate work. Also, unless it really will help things, I don't want to do work that might later be made moot by Paul adding more capabilities to WORM (not that it would be so horrible, I just want to know what the trade-offs would be and such - but it sounds like a good idea).

    > Just a couple things to think about.  I am by no means an expert in
    > this stuff, but these are just some of the things I am wondering about.

    You and nearly 90% of other people are probably more expert in this than I - I just try to fake it enough to get a regular paycheck. Stick out tongue [:P] Nah, I really dig this stuff and want to learn all that I can. Your questions are appreciated, and I hope you will entertain my ramblings (though much of them may be incoherent, ignorant or both) by continuing in this dialog.

    Thanks.

    j a s o n   b u n t i n g
  • David,

    Hey, I have done a tiny bit of reading (reading I have long wanted and needed to do) on the Repository pattern, and found something that helped me understand where it is I think you are coming from (thinking along the domain-driven design approach).

    You may have already seen this, but you can download a copy of the patterns discussed in Eric Evans' Domain-Driven Design. On page 14 of that patterns document, there is a good description of the goals of using the Repository pattern which shed some light on your comments (for me). I want to read up on other patterns to get a better idea on which seems right for this set of templates; I definitely still lean to the domain-driven approach and think this is the 'right' direction for these to go.

    Thanks again for your comments.

    j a s o n   b u n t i n g
  • I was just about to post a link to that very site.   I have not read that book yet but I plan to as soon as possible.  I had read the summaries before and I guess it's where I got the notion of repositories.  As to your question - what are the aggregate-roots - I guess the answer is "it depends" Wink [;)]   I am wondering now, too. In the docuemnt, the important lines relating to our question seem to be:

    "For each type of object that needs global access..."
    "Provide repositories only for aggregate roots that actually need direct access"

    Still, that to me does not really answer the question and begs a real-world example.  Maybe I'll order that book today...

    Here are some other threads (which you have probably already seem) that might help too:
    http://forums.asp.net/1078887/ShowPost.aspx
    http://forums.asp.net/897523/ShowPost.aspx 
    http://steve.emxsoftware.com/Domain+Driven+Design/How+Domain+Driven+Design+changed+my+way+of+thinking

    At any rate, it seems we're not alone in this quest...

  • David,

    I will take a look at those posts, thanks. I have done a lot of thinking about certain aspects of these questions in the past, but because I never took the time to read prior works on the same subject, my ignorance was obvious. Stick out tongue [:P]

    As far as which ones are the root aggregates, yes - it always depends (and that is okay). If the application is being designed up front, which we all know happens all the time Wink [;)], these should be known when code generation needs to take place. Even if they are not, the fact that we are generating code should facilitate late changes. Ultimately, I do want these templates to facilitate a more intelligent code gen process that involves specifying domain-specific ideas as metadata. I haven't thought about all of this enough yet to really be able to quantify this or explain it, but suffice it to say that people smarter than I have done similar work (see Scott's TechEd presentation for some amazing code gen). 

    I too want to see a real-world example, since my question still remains - if Order is my 'chosen' aggregate root and I want to delete one of the aggregated OrderItems, how does that look? I don't want to do something like myOrder.OrderItems[0].Delete(); because that follows the Active Record pattern. I would imagine it might be something like OrderManager.RemoveOrderItem(itemToRemove); or OrderManager.RemoveOrderItem(myOrder.OrderItems[0]); - that makes more sense to me. In fact, I am going to play with that idea a bit.

    Of course, another good book is Patterns of Enterprise Application Architecture. I have access to that book, so I will take a look to see if it provides any helpful examples.

    Thanks again for the dialogue.

    j a s o n   b u n t i n g
  • Jason,

    I am comparing pwelter's templates with your templates. Doing that, a few probably trivial/stupid questions did come up. Please bear with me as I am a complete newbie in this kind of field.

    1) You have not created any stubs for handling persistence events (IObjectNotifications). Is there a reason for this or did you simply not have time? If the later is the case would you implement it the same way pwelter did?

    2) Your templates do not have any indexers. I am not missing them but I was wondering what your reason is not to include them.

    3) Why did you decide to have a generic manager for persistence? Personally, I prefer one that is more specialist and also returns the actual class ("xxxBase.cs") rather then DataSet.

    4) Performance wise wouldn't implementing IObjectHelper and returning xxxBase class be faster then returning DataSets due to marshaling, etc.?

    Please note that is not criticism but I just try to understand the thoughts behind your approach?

    Thanks

     

     


  •  > I am comparing pwelter's templates with your templates. Doing that, a few probably
     > trivial/stupid questions did come up. Please bear with me as I am a complete newbie
     > in this kind of field.

     > 1) You have not created any stubs for handling persistence events (IObjectNotifications).
     > Is there a reason for this or did you simply not have time? If the later is the case
     > would you implement it the same way pwelter did?

    Those are planned for future iterations of the templates (these represent the simplest, complete code I could get out for a v1 release) - currently the code generated supports the bare minimum necessary to work with WORM - these are not required so I started without them. These would be stubbed similarly to the way Paul did his, I imagine, though I don't know for certain at this very moment. Perhaps I will have those done in the next week; I do plan on updating these on a regular basis (weekly, if at all possible).

     > 2) Your templates do not have any indexers. I am not missing them but I was wondering
     > what your reason is not to include them.

    Not 100% on what you mean by this (please clarify) but I do provide the most basic indexer property on the strongly-typed collections.

     > 3) Why did you decide to have a generic manager for persistence? Personally, I prefer
     > one that is more specialist and also returns the actual class ("xxxBase.cs") rather then DataSet.

     The 'generic' manager that is included in the code that is generated is merely as a thin wrapper for providing pass-through access to some of the functionality WORM provides that is not specific to any given entity. The power, in my opinion, of WORM lies in the options it gives you. Being able to simply get an ADO.NET object such as a DataSet back is good for doing reporting or some quick prototyping. That is what this class is meant to provide, and it too is not 100% complete. I hope you also noticed all of the non-generic managers that were generated . . . Wink [;)]

     > 4) Performance wise wouldn't implementing IObjectHelper and returning xxxBase class be
     > faster then returning DataSets due to marshaling, etc.?

     Not 100% sure what you asking/referring to here . . . having your business objects implement IObjectHelper will also be an option for future iterations of these templates, but personally I like and typically use the reflection-based route of things so that my objects, inasmuch as possible, have little code within them that is specific (read: coupled) to WORM. Granted, the very fact that I have variables of the type Wilson.ORMapper.ObjectHolder (i.e. a WORM-specific type) means these are tightly-coupled to this specific O/R mapping solution, but it still feels yucky (aren't all decisions based on such emotions?) to implement IObjectHelper. Yuck. Wink [;)]

     Since you bring up DataSets, either I don't understand how they are relevant to the rest of your question, or perhaps you misunderstand (from the generic manager class inclusion) that I am using DataSets somewhere I am not. Wink [;)] Perhaps you should look again at everything that is generated for this framework, simply because from your question it seems as if you think I am using them for entities.
     
     > Please note that is not criticism but I just try to understand the thoughts behind your approach?
     
     No worries - I actually enjoy well-meaning and solution-providing criticism. It is the criticism that has ill-intentions or provides no alternative solutions that I find useless. The only way to make things better is to see their failings, and if that means someone tells me that something I have done makes no sense or seems to be incorrect, so be it. I appreciate your taking time to ask questions. I hope I have provided meaningful answers and look forward to your response.
     

    j a s o n   b u n t i n g
  • Hi Jason,

    I looked at the Wilson OR Mapper for the first time yesterday and thanks to your templates was up and running in a few hours.

    I am working in the .net 2.0 space though and have many "suggesstions" (request?) if you're up for them?

    I know you mentioned you dont support generics just yet - but boy do they simplify the code and the amount of code generated.

    Let me know if you're keen.

     

     

  •    
    > I looked at the Wilson OR Mapper for the first time yesterday
    > and thanks to your templates was up and running in a few hours.

    I sure hope the templates didn't take hours to figure out - if they did, I have some work to do. Stick out tongue [:P] If it did take a while to understand them, do let me know the hardest parts or what may have been confusing so that I can either change the templates or the docs to better explain them. I really want to put together a short 'screencast' so that it will help people know what needs to be done the first time they use them, but I just have not had the time.

    > I am working in the .net 2.0 space though and have many
    > "suggesstions" (request?) if you're up for them?

    I am always open to suggestions - doesn't mean I will agree with them or have time to implement them immediately (I have my own priority list), but considering the templates are your to modify you can always do so and send the changes to me . . . or not. Smile [:)] Anyway, yes - please let me know your thoughts; I have not yet been able to spend much time in the 2.0 world because of the lack of clients using it, so any help is appreciated.

    > I know you mentioned you dont support generics just yet - but boy
    > do they simplify the code and the amount of code generated.

    Yes, it is true and I do want to get that working soon. I don't think I can give an exact date, but it is high on my list of things that should be done sooner than later.

    j a s o n   b u n t i n g
  • I posted a new version of these templates in the files section, but because moderation is turned on it may be a while (until Monday maybe?) before they show up. Until that happens, the new version can also be downloaded via this URL:

    http://www.sapientdevelopment.com/downloads/WORMFrameworkv1.1.zip

    j a s o n   b u n t i n g

  • If anyone is interested, I am working on a new version of these templates and will update my website within the next couple of weeks. The reason for a delay in updates was that I was terribly ill for nearly 2 weeks (just now getting fully over it) and I have barely kept my head above water with a client that I started work for at the beginning of February; things should be slowing down with that in the next week or two (end of the project already) and that will free me up to focus again on this.

    Some things I would like to get completed in the near future are:

    • get generics working for generated code to use with 2.0,
    • provide support for IsolatedContext, since currently the generated code creates 1 ObjectSpace instance per application, which doesn't bode well for many application types (read: most ASP.NET apps),
    • support for the IObjectHelper and IObjectNotification interfaces,
    • generation of other GetOne() methods on the managers for tables that have uniqueness constraints on columns other than the PK,
    • generation of other GetAll() methods on the managers for any foreign keys present in a table,
    • provide a way to specify a copyright statement in the generated code,
    • generate the basic <appSettings> stuff for the framework

    I am not promising any of these will definitely be done this next iteration, but they are on my list. Also in the works are those screencasts I keep saying I am going to produce (again, I got sick right when I started to work on those) and some unit test related stuff that I hope to have working (I have been doing work to extend the WilsonXmlDbClient so that unit tests can be written against apps that use WORM by providing an XML file with test data - if this doesn't make sense now, it will later when I get things working and get some screencasts related to this done).


    j a s o n   b u n t i n g
Page 1 of 3 (40 items) 123