Solved

Using an ObjectDataSource and Business Component - Design Pattern Question

Posted on 2006-11-03
13
294 Views
Last Modified: 2008-01-09
I want to populate a DetailsView with a record from my database.

However I need to perform some conditional logic before passing the data to my ObjectDataSource.

I was wondering the best way to accomplish this. Obviously I cant create a DataReader and pass that back to the ObjectdataSource as I would not be able to perform the conditional logic.

This is how I see it being done

I have to create an object (class) to represent the data held in the record.

Then I need to get the record using ExecuteNonQuery. Then pass some field vales through the condtional statments.

Then save the field values (and revised values) to my object and send them back to the ObjectDataSource.

Here is some code that I've already written

Public Class WeddingPolicyDetails
    Public PurchaseID As Integer
    Public WeddingDate As DateTime
    Public DobAge As String
    ' etc etc
End Class

Public Class PolicyAdmin

    Public Function GetWeddingPolicyByID(ByVal purchaseID As String) As WeddingPolicyDetails
        ' Create the Connection object
        Dim connection As New SqlConnection(connectionString)
        Dim details As New WeddingPolicyDetails()

        ' Create and initialize the Command object
        Dim selectString = "SELECT WeddingPolicies.wpol_id, WeddingPolicies.wpol_entrydate, WeddingPolicies.wpol_customerid, WeddingPolicies.wpol_weddingdate, WeddingPolicies.wpol_coverlevel, WeddingPolicies.wpol_marquee, WeddingPolicies.wpol_liability, WeddingPolicies.wpol_groomname, WeddingPolicies.wpol_groomdob... etc WHERE (WeddingPolicies.wpol_id = @purchaseID)"
        Dim command As SqlCommand = New SqlCommand(selectString, connection)
        command.Parameters.AddWithValue("@purchaseID", SqlDbType.Int).Value = purchaseID

        Try

            ' Open the connection and get the data
            connection.Open()
            Dim reader As SqlDataReader = command.ExecuteReader()

            While reader.Read()

                ' Perform conditional logic...
                ' If the Date of Birth field does not have a value, use the age field
                If reader("wpol_dob") Is DBNull.Value Then
                    details.DobAge = reader("wpol_age")
                Else
                    ' Use the Age field and the Date of Birth field
                    details.DobAge = reader("wpol_age") & " (Date of Birth: " & reader("wpol_dob") * ")"
                End If

                ' Load the object with values
                details.PurchaseID = reader("wpol_id")
                details.WeddingDate = reader("wpol_weddingdate")
                ' Continue loading the object with DataReader values

            End While
        Catch ex As Exception
            ' Close the connection and throw the exception
            connection.Close()
            Throw ex
        End Try

        Return details

    End Function

Is this correct? Is there a better way to do it? Doing it this way means I have to spend a fair amount of time creating the WeddingPolicyDetails object.

Perhaps there is a way of interacting with a Datareader object (i.e. get the datareader, amend some values within it and then return the datareader (as opposed to returning the WeddingPolicyDetails object.
0
Comment
Question by:g-spot
  • 6
  • 4
  • 3
13 Comments
 
LVL 96

Expert Comment

by:Bob Learned
ID: 17866028
Where/how is the ObjectDataSource defined?

Bob
0
 

Author Comment

by:g-spot
ID: 17866102
Hi Bob

The ObjectDataSource is declared in the aspx file:

        <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" SelectMethod="GetWeddingPolicyByID" TypeName="PolicyAdmin">
          <SelectParameters>
            <asp:QueryStringParameter DefaultValue="100182" Name="purchaseID" QueryStringField="purchaseid" Type="String" />
          </SelectParameters>
        </asp:ObjectDataSource>
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 17866135
I don't understand why there is ObjectDataSource1, and something different in GetWeddingPolicyByID.  Couldn't you just use an SqlDataSource object to get the work done?

Bob
0
 

Author Comment

by:g-spot
ID: 17866209
Hi Bob

ObjectDataSource1 calls the GetWeddingPolicyByID function which allows me to perform the conditonal logic on the data before sending the data to the ObjectDataSource.

If I used an SqlDataSource I would not be able to perform the conditional logic as the data would be passed straight from the database to the SqlDataSource.

0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 17866218
Are you talking about this logic?

               If reader("wpol_dob") Is DBNull.Value Then
                    details.DobAge = reader("wpol_age")
                Else
                    ' Use the Age field and the Date of Birth field
                    details.DobAge = reader("wpol_age") & " (Date of Birth: " & reader("wpol_dob") * ")"
                End If

Bob
0
 

Author Comment

by:g-spot
ID: 17866243
Yes.

I cant be sure if there will be a value for the date of birth (dob) field so I have to check and if not, I have to send back the value from the age field which should be there in the absence of a date of birth value.
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 96

Accepted Solution

by:
Bob Learned earned 150 total points
ID: 17866252
You can do this within the SQL statement with a CASE block.

Bob
0
 

Author Comment

by:g-spot
ID: 17866430
Ah ha! Yes, that might be the answer. Im no SQL expert so could you provide an example. Won't there be a problem in that I'm either going to be returning a date vale if Date of birth exists or an integer if date of birth doesnt exist.
0
 
LVL 3

Expert Comment

by:k3opie
ID: 17866792
I needed to manipulate some data before binding one time.  Yes, i was using an object datasource and bussiness objects too.  

WORDS OF WARNING: If you can perform the data transformation in SQL then by all means The LearnedOne is correct, do it there!!!  It's going to be much easier and much more efficient.   In my case i couldn't, let me tell you what i did.  

http://msdn2.microsoft.com/en-gb/library/system.web.ui.webcontrols.objectdatasource.selected.aspx
You can hook into the object data source selected event.

The event has a property in its event argument called returnValue .. ususally gotten using e.returnValue()  (may not be proper case)

So, basically the e.returnValue in this event contains your underlying datasource from the object datasource select method.  There are two really nice things about hooking into the object data source here.
1.) Your data has been queried from the underlying data source and is packaged nicely and ready for you to manipulate.
2.) The data hasn't bound yet and any changes you make to the underlying data here will be shown in the bound control.

Yeah, this is pretty sweet.  You'll likely have to cast your e.ReturnValue as the type of underlying data you are using in your object data source to get access to all the properties, but this is straight forward using DirectCast, if you hardcode the type.
http://msdn2.microsoft.com/en-us/library/7k6y2h6x.aspx

So basic recap.  
1.) Hook object data source selected event.
2.) Cast e.ReturnValue as your desired bussiness type.
3.) Manipulate bussiness data.
4.) Sit back and watch the object data source bind the data up!

Now you should be able to tweak the data, VIA the objectdatasource any way your heart desires without having to rebind or send the data around or messing this or that up.  Just grab the underlying data, and edit it. Sit back and watch the edited data bind up to your objects.    So sweet.

GoodLuck,
Andrew



0
 

Author Comment

by:g-spot
ID: 17880427
Hi Andrew

Thanks for your post.

I'm not sure what you mean 'Cast e.ReturnValue as your desired bussiness type'.

I've changed my Business Object function to return a DataReader:

    Public Function GetWeddingPolicyByID(ByVal purchaseID As String) As SqlDataReader

        ' Create the Connection object
        Dim connection As New SqlConnection(connectionString)
        Dim details As New WeddingPolicyDetails()

        ' Create and initialize the Command object
        Dim selectString = "SELECT WeddingPolicies.wpol_id, WeddingPolicies.wpol_entrydate, WeddingPolicies.wpol_customerid, WeddingPolicies.wpol_weddingdate, WeddingPolicies.wpol_coverlevel, WeddingPolicies.wpol_marquee, WeddingPolicies.wpol_liability, WeddingPolicies.wpol_groomname, WeddingPolicies.wpol_groomdob, WeddingPolicies.wpol_groomage, WeddingPolicies.wpol_bridename, WeddingPolicies.wpol_bridedob, WeddingPolicies.wpol_brideage, WeddingPolicies.wpol_soe, WeddingPolicies.wpol_referral, WeddingPolicies.wpol_clientip, Transactions.tra_id, Transactions.tra_policyid, Transactions.tra_firstname, Transactions.tra_lastname, Transactions.tra_address1, Transactions.tra_address2, Transactions.tra_city, Transactions.tra_county, Transactions.tra_postcode, Transactions.tra_amount, Transactions.tra_cctype, Transactions.tra_ccname, Transactions.tra_ccnumber, Transactions.tra_ccstart, Transactions.tra_ccend, Transactions.tra_ccissue, Transactions.tra_ccv FROM WeddingPolicies INNER JOIN Transactions ON WeddingPolicies.wpol_id = Transactions.tra_policyid WHERE (WeddingPolicies.wpol_id = @purchaseID)"
        Dim command As SqlCommand = New SqlCommand(selectString, connection)
        command.Parameters.AddWithValue("@purchaseID", SqlDbType.Int).Value = purchaseID

        Try

            ' Open the connection and get the data
            connection.Open()
            Return command.ExecuteReader(CommandBehavior.CloseConnection)

        Catch ex As Exception
            ' Close the connection and throw the exception
            connection.Close()
            Throw ex
        End Try

    End Function

and ObjectDataSource1_Selected is:

    Protected Sub ObjectDataSource1_Selected(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ObjectDataSourceStatusEventArgs) Handles ObjectDataSource1.Selected

        Dim reader As SqlDataReader = e.ReturnValue

        Dim groomBirthDetails As String

        While reader.Read()

            ' Perform conditional logic...
            ' If the Date of Birth field does not have a value, use the age field
            If reader("wpol_groomdob") Is DBNull.Value Then
                groomBirthDetails = reader("wpol_groomage")
            Else
                ' Use the Age field and the Date of Birth field
                groomBirthDetails = reader("wpol_groomage") & " (Date of Birth: " & reader("wpol_groomdob") & ")"
            End If

        End While

    End Sub

Not sure what to do next?
0
 
LVL 3

Assisted Solution

by:k3opie
k3opie earned 100 total points
ID: 17881283
Ok, so if you are going to use the object data source you don't want your bussiness objects returning a data reader, usually.  

I think the best bet for you is going to be to get this done in SQL.  

I'll try to elaborate further here though.
I'm by no means an expert on design patterns and  business components.  First off I don't ususallly have a sql reader and an object data source any where near each other.  If you are going to design a bussiness objects, it should be an actual class with properties for its fields.  Your DAL should go out and get the data from sql and populate these objects with the information. Any queries to the database should return a collection of custom bussiness objects.  If you're mixing sqlReader and object data sources your stepping in the wrong direction.

One of the nicest things about the object data source is that it allows you to design a nice seperation between your DAL and your BLL ... Your DAL should go out and get the data and put this data into your bussiness objects.  The DAL should only be accessed THROUGH the BLL.  If you are using sql or the sqldatasource then you coupling you DAL and BLL.

That is likely very confusing but you should read up on further 3 layer architectures .

If you did want to use the code above from your previous post in a manner similar to what i was talking about it would be something like the following.  Although i don't suggest doing this because it has a feeling of bad coding style to me. Mixing object data source and sql reader just doesn't seem like a good idea to me.


Protected Sub ObjectDataSource1_Selected(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ObjectDataSourceStatusEventArgs) Handles ObjectDataSource1.Selected

        Dim reader As SqlDataReader = e.ReturnValue

        Dim groomBirthDetails As String

        While reader.Read()

            ' Perform conditional logic...
            ' If the Date of Birth field does not have a value, use the age field
            If reader("wpol_groomdob") Is DBNull.Value Then
                reader("wpol_groomdob") = reader("wpol_groomage")
            Else
                ' Use the Age field and the Date of Birth field
                reader("wpol_groomdob") = reader("wpol_groomage") & " (Date of Birth: " & reader("wpol_groomdob") & ")"
            End If

        End While

    End Sub


Now when your objects bind the wpol_groomdob field will contain the proper information and you can use it like normal.

good luck,
andrew.  

Sorry if my post was confusing. and yes, designing a proper bussiness layer is very very time consuming.
0
 

Author Comment

by:g-spot
ID: 17881719
Hi Andrew

Thanks for your further post.

To be honest I was looking for a fast rough and ready way to intercept certain record values from the database, run some of them through a conditional statement and pass all the record values to a DetailsView.

I have looked at various ways of doing this and one of the first thoughts was creating a WeddingPolicy object and passing it to the DataSource. As I mentioned in my first post I felt this would be too time-consuming.

You final coding suggestion was another thought of mine but the SqlDataReader is readonly so I can't alter the values.

I guess I'm going have to go with Bob's initial suggestion of doing the work within SQL. Therefore I will award the the answer to him with a (valuable) assist from you.

G
0
 
LVL 3

Expert Comment

by:k3opie
ID: 17881730
go with bob 100%.  He's def got the best answer for you.

0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

IntroductionWhile developing web applications, a single page might contain many regions and each region might contain many number of controls with the capability to perform  postback. Many times you might need to perform some action on an ASP.NET po…
User art_snob (http://www.experts-exchange.com/M_6114203.html) encountered strange behavior of Android Web browser on his Mobile Web site. It took a while to find the true cause. It happens so, that the Android Web browser (at least up to OS ver. 2.…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

23 Experts available now in Live!

Get 1:1 Help Now