CodeSmith Community
Your Code. Your Way. Faster!

problem with a non-abstract ProviderBase class

Latest post 06-01-2007 3:13 PM by ToddMoon. 26 replies.
  • 01-29-2007 7:11 AM

    • chrisis
    • Not Ranked
    • Joined on 01-29-2007
    • Posts 6
    • Points 300

    problem with a non-abstract ProviderBase class

    I am in the process of adding methods to my provider class 'SqlCustomerProvider'. The method is called 'GetCustomer()'. The Nettiers way or working does not allow me direct access to this class but instead offers me the 'CustomerProviderBase' class as an interface. Now, what I have done it added my method as an abstract method in this base class, and use an implementation is my SQl subclass.

    public abstract partial class CustomerProviderBase : CustomerProviderBaseCore
    {
       public abstract int GetCustomer();
    }

    public partial class SqlCustomerProviderBase : CustomerProviderBase
    {
      
    }


    public partial class SqlCustomerProvider : SqlCustomerProviderBase
    {
       public abstract int GetCustomer()
       {
          //implementation code
       } 
    }

    The problem is that this does not compile. Because the intermediate class 'SqlCustomerProviderBase' is not declared abstract, I am forced to add an implementation of the method to this class. Unfortunately, this class is generated so al my changes are overwritten at every new generation.

    It is my belief that this class should be declared abstract. It ends with 'base' and only had a protected constructor, indicating it is not meant for instantiation.

    Is this a bug or is there a particular reason why it is implemented like this? Perhaps this is a known issue?

    • Post Points: 125
  • 01-29-2007 8:45 AM In reply to

    • swin
    • Top 10 Contributor
    • Joined on 06-14-2006
    • London, UK
    • Posts 925
    • Points 34,785

    Re: problem with a non-abstract ProviderBase class

    Why are you adding your method to the SqlClient layer?

    When I hand craft any data access methods I normally add them into the Data layer and then link them into my service layer (Component layer).  This works for me, although I'm open to suggestions if this isn't right.

    However, did you know you can get NetTiers to wire up your custom stored procs automatically? Name them so they fit the "CustomStoredProceduresStartWith" pattern and you'll get all the methods created for you so you don't have to do anything yourself (If you can't rename your procs you can always write a wrap-around with the correct name)

    hth

    swin 

     

    ------------------------------------------------- Member of the .NetTiers team -------------------------------------------------
    • Post Points: 35
  • 01-29-2007 9:43 AM In reply to

    • chrisis
    • Not Ranked
    • Joined on 01-29-2007
    • Posts 6
    • Points 300

    Re: problem with a non-abstract ProviderBase class

    Granted, implementing stored procs and then regenerating is also possible. However, when not using stored procedures (for very simple queries) I was under the impression that I was free to add methods of my own. After all, not everything can be generated, right? In that case, my problem surfaces. Of course, I can work around this problem by making the intermediate class abstact (by adding a partial partner) or if I choose to be practical, I would change the top-level methods from abstract into virtual. The first option's problem is that regeneration will remove my partial file from the project whereas the second option is simple bad coding ;)

    So am I 'allowed' to edit anything in my DataAccess classes or should I only use generate code?

    • Post Points: 35
  • 01-29-2007 10:13 AM In reply to

    • swin
    • Top 10 Contributor
    • Joined on 06-14-2006
    • London, UK
    • Posts 925
    • Points 34,785

    Re: problem with a non-abstract ProviderBase class

    If you add your custom method to the "yourentityProviderBase.cs" in the Data layer (Bases folder), you can pretty much do what you want with regards to data access.

    We tend to do all db access in stored procs, but theres no reason why you couldn't just execute a SQL command there. For example using the Northwind Customers entity you could do this...

    public abstract partial class CustomersProviderBase : CustomersProviderBaseCore
        {
            public System.Data.DataSet GetCustomer( string customerId )
            {
                return DataRepository.Provider.ExecuteDataSet(
                        CommandType.Text,
                        string.Format( "SELECT * FROM CUSTOMERS WHERE id = '{0}'", customerId ) );

            }

        }

    *warning untested code!*

    Check out the DataRepository.Provider for other Execute methods that have been exposed from teh underlying Entlib. 

    BTW; Did you realise that NetTiers generates a "GetBy" method for all indexes on your table? i.e. GetByCustomerName() 

    hth

    swin
     

    ------------------------------------------------- Member of the .NetTiers team -------------------------------------------------
    • Post Points: 35
  • 01-29-2007 7:09 PM In reply to

    Re: problem with a non-abstract ProviderBase class

    Here is what I have been doing and it has been working fine for me.  I would be very interested if there is a better way or if this is good!  I believe you are correct that you should only add your implementation code in the SqlCustomerProvider class. But you can also add another partial class of SqlCustomerProviderBase into the same file as the SqlCustomerProvider class (or it can be in another separate file).  One of the big reasons for partial classes is so that generated code can be separated from custom code but still belong to the same class.  No code is changed inside of generated classes so nothing gets lost.  Here is my example. 

     Inside of CustomerProviderBase.cs

    public abstract partial class CustomerProviderBase : CustomerProviderBaseCore
    {
        public abstract int GetCustomer();
    }

     Inside of SqlCustomerProvider.cs

    public partial class SqlCustomerProvider : SqlCustomerProviderBase
    {
        public override int GetCustomer
        {
            //Concrete implementation code here
        }
    }

    public abstract partial class SqlCustomerProviderBase
    {
        public abstract override int GetCustomer();

     

    Stan

    • Post Points: 35
  • 01-30-2007 1:41 AM In reply to

    • chrisis
    • Not Ranked
    • Joined on 01-29-2007
    • Posts 6
    • Points 300

    Re: problem with a non-abstract ProviderBase class

    Thanx for your answer. However, my problem had to do with the structure of the dataaccess classes in nettiers, not with specific funtioanlity. You example method lives in the CustomerProviderbase. However, the correct place (as far as I can see) is in the SqlCustomersProvider class since that contains the sql sever implementations. Then I am back at my original problem...I am forced to make the base class of SqlCustomersProvider into an abstract class like I explained in my first post.

    Let me rephrase my question: if the SqlCustomersProviderBase class contains only a protected constructor and is meant as a base class, then why is it not declared abstract? This would prevent my problem without any negative side-effects. I would like to suggest that you consider changing this in the next release of the templates it you agree with this assessment.

    • Post Points: 35
  • 01-30-2007 3:14 AM In reply to

    • swin
    • Top 10 Contributor
    • Joined on 06-14-2006
    • London, UK
    • Posts 925
    • Points 34,785

    Re: problem with a non-abstract ProviderBase class

    I think I'll have to defer to someone who was more integral to the design of NetTiers (Robert?) as I've only shown what works for me. 

    "Stan the Man"'s (I wondered what happened to Mr. Collymore Wink) suggestion seems like a good option though.

    Robert can you comment on the nature of the Data.SqlClient layer and what customisation is allowed/expected?

    swin 

    ------------------------------------------------- Member of the .NetTiers team -------------------------------------------------
    • Post Points: 5
  • 01-30-2007 3:42 AM In reply to

    • chrisis
    • Not Ranked
    • Joined on 01-29-2007
    • Posts 6
    • Points 300

    Re: problem with a non-abstract ProviderBase class

    My apologies Stan...i missed your reply and only saw the last reply instead...

    I had already used your suggestion. This does work (in fact: you do not even need to add the "public abstract override int GetCustomer();" since marking the class as 'abstract' is actually sufficient. There are 3 things i can say about this:

     1: I think the class should be abstract by default. I still think you should change this in coming releases

    2: when regenerating the dataaccesslayer the project file is overwritten and my partial class is removed from the projectfile.

    3: After reconsideration I do not understand why there is a division between 'SqlCustomerProviderBase' and 'SqlCustomerProvider'. Would it not be much easier if you would change the class 'SqlCustomerProviderBase'  to 'SqlCustomerProvider' ? This would remove a layer in the hierarchy while still alowing me to add code in my partial class. Like this:

    public abstract partial class CustomerProviderBase : CustomerProviderBaseCore
    {
        public abstract int GetCustomer();
    }

     public abstract partial class SqlCustomerProvider : CustomerProviderBase
    {
        //this is the class that is now SqlCustomerProviderBase. It contain onmly generated code

    public partial class SqlCustomerProvider
    {
        //this is the partial partner that I am allowed to edit. It no longer subclasses explicitely because it already has a baseclass

    }

    Is there any reason why this structure is not a valid option. It seems to be simpler.? 

     

    • Post Points: 35
  • 01-30-2007 10:43 AM In reply to

    • GRAW
    • Top 25 Contributor
    • Joined on 06-23-2006
    • Posts 157
    • Points 4,560

    Re: problem with a non-abstract ProviderBase class

    Chrisis,

    you could also have a virtual default implementation of GetCustomer() in the CustomerProvider that just raises a not implemented exception.  Then in SqlCustomerProviderBase just override the GetCustomer() method and provide your implementation, without having to create an implementation in SqlCustomerPoviderBase.

     So instead of:

    public abstract partial class CustomerProviderBase : CustomerProviderBaseCore
    {
       public abstract int GetCustomer();
    }

    u can do:

    public abstract partial class CustomerProviderBase : CustomerProviderBaseCore
    {
       public virtual int GetCustomer()

        {

            throw System.NotIimplementedException();

        }
    }
     

    "Small is the number of them that see with their own eyes, and feel with their own hearts" Albert Einstein
    • Post Points: 5
  • 01-30-2007 10:44 AM In reply to

    • bgjohnso
    • Top 10 Contributor
    • Joined on 09-15-2005
    • Spokane, WA
    • Posts 767
    • Points 22,665

    Re: problem with a non-abstract ProviderBase class

    chrisis:

     1: I think the class should be abstract by default. I still think you should change this in coming releases

     

    I agree with you on this one.  I don't see any drawbacks to making this class abstract.

    chrisis:

    2: when regenerating the dataaccesslayer the project file is overwritten and my partial class is removed from the projectfile.

    There is a setting called CustomCodeFolderName (which defaults to App_Code).  If you place your custom files in this directory, they will be added back in to the project after regeneration. 

     

    chrisis:

    3: After reconsideration I do not understand why there is a division between 'SqlCustomerProviderBase' and 'SqlCustomerProvider'. Would it not be much easier if you would change the class 'SqlCustomerProviderBase'  to 'SqlCustomerProvider' ? This would remove a layer in the hierarchy while still alowing me to add code in my partial class. Like this:

    ...

    Is there any reason why this structure is not a valid option. It seems to be simpler.? 

    We have had quite a few discussions over when to just use partial classes and when to use base classes and inheritance.  In the end, I think the combination of the two is the best route.  In this instance, if you were to follow your suggestion, then you would prevent anyone from overriding the default implementation.  With partial classes, you can extend the implementation, but you can not change any existing code.  So, if you didn't like the way the Delete method worked (or wanted to add auditing for example) you would be stuck.  However, using the base class and inheritance, you can simply override the base implementation with whatever you would like.

    Ben Johnson
    ------------------------------
     Member of the .NetTiers team
     Visit http://www.nettiers.com
    ------------------------------

    • Post Points: 35
  • 01-30-2007 10:54 AM In reply to

    • swin
    • Top 10 Contributor
    • Joined on 06-14-2006
    • London, UK
    • Posts 925
    • Points 34,785

    Re: problem with a non-abstract ProviderBase class

    Ben,

    Could you comment on the nature of the Data and Data.SqlClient layers and what customisation is allowed/expected in each?

    Thanks

    swin 

    ------------------------------------------------- Member of the .NetTiers team -------------------------------------------------
    • Post Points: 35
  • 01-30-2007 11:11 AM In reply to

    • bgjohnso
    • Top 10 Contributor
    • Joined on 09-15-2005
    • Spokane, WA
    • Posts 767
    • Points 22,665

    Re: problem with a non-abstract ProviderBase class

    Hey swin,

     Well, I am definitely not the most knowledgeable on this subject, but I can try and explain my understanding of it... 

    From what I know, this is all based on an abstract provider model.  Your code talks to the abstract provider and doesn't really care where the data comes from (SQL Server, Oracle, web service, xml file, etc).  The intent is that through configuration you can change the provider (ie from SQL Server to web services) without having to change any code within your application.  The Data project is the abstract layer that contains all the actions that can be performed.  The SqlClient client layer is the concrete implementation of the abstract layer.  This is where the SQL specific code goes.  I think that Chrisis is doing the right thing.  First you add an abstract/virtual implementation of your method to the Data layer.  Then you add the concrete implementation of that method in the SqlClient project.  If you want to be complete, you would also add implementations in all other concrete providers (ie web service provider).  Now swin, what you have suggested will "technically" work.  By adding your code directly in the Data layer you can successfully talk to your database and get the data you want.  The only problem is that you are now limited to only talking to SQL server (actually, any provider that understands the code you implemented).  You have basically taken away the advantage of the abstract provider model.  Like I said, this is fine but you just have to understand the limitation that you have imposed upon yourself.

    Well, that's about all I know (or think I know).  If I have mispoken, please feel free to correct me.

    Ben Johnson
    ------------------------------
     Member of the .NetTiers team
     Visit http://www.nettiers.com
    ------------------------------

    • Post Points: 35
  • 01-30-2007 12:01 PM In reply to

    Re: problem with a non-abstract ProviderBase class

    Ben is 100% correct on all those points.

    Robert Hinojosa
    -------------------------------------
    Member of the Codesmith Tools, .netTiers, teams
    http://www.nettiers.com
    -------------------------------------
    • Post Points: 35
  • 01-31-2007 8:02 AM In reply to

    • chrisis
    • Not Ranked
    • Joined on 01-29-2007
    • Posts 6
    • Points 300

    Re: problem with a non-abstract ProviderBase class

    Okay. Thanx for all the input everyone. I think I will proceed by adding the extra partial class and follow the suggestion to place it in a special folder. I can't seem to bring myself to use the 'easier' virtual method solition because I think that is a step away from the code I want to write.

    As far as the issue of partial class versus inherited class is concerned....I have had to make the same decision in a custom dataAccess layer and I arrived at the same conclusion ;).. Because I did not use class-generation to the extent Nettiers does I was pretty satisfied with my solution. However, since modifying the templates is a valid option for a nettiers project it might be worth considering making the default Nettiers class hierarchy somewhat simpler. Anyone knowledgeable in the field of OO could modify the templates if needed, but the default could be a bit easier to understand if there was less inheritance.

     Just my two cents :)

     

     

    • Post Points: 35
  • 01-31-2007 1:16 PM In reply to

    • bgjohnso
    • Top 10 Contributor
    • Joined on 09-15-2005
    • Spokane, WA
    • Posts 767
    • Points 22,665

    Re: problem with a non-abstract ProviderBase class

    Hmmm...  I'm not sure why the virtual method is a "step away" from the code you want.  I actually like it.  By making it virtual and throwing a NotImplemented exception, you leave it up to the concrete providers as to whether or not to implement it.  For example, you may want to expose it through the Sql provider but not through the web service provider.  If someone tried to access that method through the web service, they would get a NotImplemented exception.  By making it abstract, you force every concrete provider to at least stub out the method to even compile your project.  This may be a moot point as I don't think a lot of people are using multiple providers, but I think it's worth mentioning.

     As to your second point, yes the class heirarchy in NetTiers is complex (especially at the provider level).  However, we have arrived at this point through a logical progression of events.  We started out with a simpler heirarchy, but we always ended up where people couldn't modify the things they wanted to modify and still be able to regenerate the code at any point.  Now, if you were writing this code by hand, would you have 4+ levels of inheritance in the provider classes?  Absolutely not.  However, we are using a code generator for a reason.  As I see it, I see two main goals of NetTiers; (1) re-generate your project at any time and not lose any customizations and (2) be able to extend and modify any generated classes.  Really this just boils down to flexibility.   Unfortunately, flexibility and complexity are often directly correlated in that as one increases so does the other.  I'm not trying to lecture you, but rather I'm just trying to help explain how we ended where we are today.

    As always, your comments are appreciated.

    Ben Johnson
    ------------------------------
     Member of the .NetTiers team
     Visit http://www.nettiers.com
    ------------------------------

    • Post Points: 65
Page 1 of 2 (27 items) 1 2 Next > | RSS
Copyright © 2008 CodeSmith Tools, LLC
Powered by Community Server (Commercial Edition), by Telligent Systems