4

If I have an ObjectDataSource setup like:

<asp:ObjectDataSource 
    ID="ObjectDataSource1" 
    runat="server" 
    DataObjectTypeName="Employee"
    InsertMethod="Insert" 
    UpdateMethod="Update"
    DeleteMethod="Select" 
    TypeName="EmployeeDB">
</asp:ObjectDataSource>

and a data/business object with methods like:

public class EmployeeDB
{
    public void Insert(Employee emp)
    public int Update(Employee emp)
    public bool Delete(int id)
}

How do I get the objectdatasource to use the Delete method with the parameter that is not an Employee object?

If this is not possible, what is the recommended alternative architecture?

Edit:

To clarify, I want to use the method signature on my data/business object as shown above, however if I try to allow an Employee object to be passed into some of the methods using DataObjectTypeName, then I seemingly lose the ability to have some methods take just an integer id for instance.

If I do not use the DataObjectTypeName, then I have to place all the method parameters in the ObjectDataSource and change the methods on the data/business object to match, this seems like a bad design choice because as the Employee object changes I will have to update each of these methods. Is there a better architecture?

Laz
  • 3,474
  • 9
  • 33
  • 46
  • in my view, use ObjectDataSource itself is a bad design. Microsoft created those drag and drop control to speed development, but it's really NOT good architecture by any means. – J.W. May 28 '09 at 02:44
  • @J.W. Of the 'drag and drop' controls the ObjectDataSource is one of the only 'out-of-the-box' gateways from the UI directly into your facade layer without handling things by events in your code behind. I credit it for that at least. – Brendan Kowitz May 28 '09 at 07:24

8 Answers8

1

Here is solution and it is working for me for update operation then delete far easier than update :

  1. Create Class to pass parameter. For Example : I am passing paramter for Usermaster table : UserMasterDT :

    public UserMasterDT(int userid, int roleid, string Firstname, string )
    {
        this.muserid = userid;
        this.mroleid = roleid;
        this.mfirstname = Firstname;
        this.mlastname = Lastname;
    }
    
    //Here set this prop as DUMMY output variable, that u used everywhere to get   output value
    public int iRecUpdated
    {
        get { return mrecupdated; }
        set { mrecupdated = value; }
    }
    
  2. I am binding objectdatasource to formview for update uperation.Set objectdatasource as follows :

    <asp:ObjectDataSource ID="odsUser" runat="server" 
        TypeName="MMCTaxINTLXMLValidation.UserBLL"
        SelectMethod="GetUserRoleByUserId" 
        DataObjectTypeName="MMCTaxINTLXMLValidation.UserMasterDT"  
        OldValuesParameterFormatString="original_{0}" 
        UpdateMethod="UpdateUserWithTransaction" onupdated="odsUser_Updated">        
        <SelectParameters>
            <asp:QueryStringParameter  Name="iUId" QueryStringField="UserId" Type="Int32" 
                DefaultValue="-1" />
        </SelectParameters>
        <UpdateParameters>
            <asp:Parameter  Name="UserId" Type="Int32" ConvertEmptyStringToNull="true" />
            <asp:Parameter  Name="RoleId" Type="Int32" ConvertEmptyStringToNull="true" />
            <asp:Parameter  Name="Firstname" Type="String"  ConvertEmptyStringToNull="true" />
            <asp:Parameter  Name="Lastname" Type="String" ConvertEmptyStringToNull="true" />       
            <asp:Parameter  Name="BirthDate" Type="String" ConvertEmptyStringToNull="true" />
            <asp:Parameter  Name="MMCEmail" Type="String" ConvertEmptyStringToNull="true" />
            <asp:Parameter  Name="Homecontact" Type="String" ConvertEmptyStringToNull="true" />
            <asp:Parameter  Name="Officecontact" Type="String" ConvertEmptyStringToNull="true" />
            <asp:Parameter  Name="Cellcontact" Type="String" ConvertEmptyStringToNull="true" />
            <asp:Parameter  Name="Logon" Type="String" ConvertEmptyStringToNull="true" />
            <asp:Parameter  Name="Password" Type="String" ConvertEmptyStringToNull="true" />
            <asp:Parameter  Name="PasswordQ1" Type="String" ConvertEmptyStringToNull="true" />
            <asp:Parameter  Name="PasswordA1" Type="String" ConvertEmptyStringToNull="true" />               
        </UpdateParameters>
    </asp:ObjectDataSource>
    

    NOTICE THERE IS NO ANY OUTPUT PARAMTER HERE

  3. Now, IN U R BLL In update method, pass and return UserMasterDT as input and output. DO NOT PASS SEPERATE PARAMETER AND OUT VARAIBLE . Write code like :

    HERE I AM PASSING UserMasterDT AS IN AND OUT

    [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Update, true)]
    public UserMasterDT UpdateUserWithTransaction(UserMasterDT tempuser)
    {
        int iRecUpdated = -1;
        Adapter.BeginTransaction();
    
        try
        {
            string sFlag = "UpdateUserRole";
            int iUserId = tempuser.UserId;
            int iRoleId = tempuser.RoleId;
            string sFirstname = tempuser.Firstname;
            string sLastname = tempuser.Lastname;
            int? iReturnData;
    
            //THIS OUT IS FROM MY SQL STORED PROCE NOT WITH OBJECTDATASOURCE OUT PARAMETER. IT HAS NOTHING TO DO WITH OBJECT DATA SOUCE.
            Adapter.UpdateUserRole(sFlag,iUserId,iRoleId,sFirstname,sLastname,out iReturnData);
    
            if (iReturnData == 1)
            {
                iRecUpdated = 1;
                this.Adapter.CommitTransaction();
            }
            else if (iReturnData == null)
                iRecUpdated = -1;
    
            //What ever is return, set it back to UserMasterDT's iRecUpdated prop
            tempuser.iRecUpdated = iRecUpdated;
            return tempuser;
        }
        catch (Exception ex)
        {
            if (ex != null)
            {
                Adapter.RollbackTransaction();
                //CustomEX objCUEx = new CustomEX(ex.Message, ex);
                ex = null;
                iRecUpdated = -1;    //-1 : Unexpected Error
                //What ever is return, set it back to UserMasterDT's iRecUpdated prop
                tempuser.iRecUpdated = iRecUpdated;
                return tempuser;
            }
        }
        finally
        {
            tempuser.iRecUpdated = iRecUpdated;
        }
    
        //Return tempuser back
        return tempuser;
    }
    
  4. then in aspx.cs page read property of UserMasterDT as follows :

    if (e.Exception == null)
    {
        UserMasterDT tempuser = (UserMasterDT) e.ReturnValue;
        lblMsg.Text = "Record Updated : " + tempuser.iRecUpdated.ToString();
    }
    
  5. My stored proc is :

    set ANSI_NULLS ON
    
    create PROCEDURE [dbo].[UpdateUserRole]
    (
        @sFlag varchar(50),
        @iUserId int,
        @iRoleId int,
        @sFirstname varchar(50),
        @sLastname varchar(50),
        @iReturnData int output
    )
    as
    Begin
        Declare @errnum as int
        Declare @errseverity as int
        Declare @errstate as int
        Declare @errline as int
        Declare @errproc as nvarchar(100)
        Declare @errmsg as nvarchar(4000)
    
    
        -----------------------
        if @sFlag = upper('UPDATEUSERROLE')
        begin
            begin try
                begin tran
                    --Update User Master Table
                    UPDATE    tblUserMaster
                    SET  Firstname = @sFirstname,
                    Lastname = @sLastname,
                    WHERE UserId = @iUserId
    
                    --Update tblUserRolesTran Table
                    update  tblUserRolesTran
                    set roleid = @iRoleId
                    where Userid = @iUserId
    
                commit tran -- If commit tran execute then trancount will decrease by 1
    
                -- Return Flag 1 for update user record and role record
                SET @iReturnData = 1
    
            end try
            begin catch
                IF @@Trancount > 0
                    -- Get Error Detail In Variable
                    Select  @errnum =@@ERROR,
                    @errseverity = ERROR_SEVERITY(),
                    @errstate = ERROR_STATE(),
                    @errline = ERROR_LINE(),
                    @errproc = ERROR_PROCEDURE(),
                    @errmsg = ERROR_MESSAGE()
    
                    rollback tran
    
                    -- To see print msg, keep raise error on, else these msg will not be printed and dislayed
                    print '@errnum : ' + ltrim(str(@errnum ))
                    print '@errseverity : ' + ltrim(str(@errseverity))
                    print '@errstate : ' + ltrim(str(@errstate))
                    print '@errline : ' + ltrim(str(@errline))
                    print '@errproc : ' + @errproc
                    print '@errmsg : ' + @errmsg
    
                    --Raise error doesn't display error message below 50000
                    --So we have to create custom message and add to error table using  sp_addmessage ( so_addmessage is built-in sp)
                    --In custom error message we have line number and error message
                    Declare @custerrmsg as nvarchar(4000)
                    Select @custerrmsg =  'Proc: UpdateUserRole, Line: ' + ltrim(str(@errline)) +  ': ' + @errmsg
    
                    if (@errnum < 50000)
                        EXEC SP_ADDMESSAGE @msgnum = 50002, @severity = 16,  @msgtext = @custerrmsg, @replace = 'REPLACE'
    
    
                    --After adding custom error message we need to raise error
                    --Raise error will appear at client (.net application)
                    RAISERROR(50002,16,1)
            end catch
            end
            set nocount off
    End
    

Hope this helps you whatever u need to do. sairam

takrl
  • 6,356
  • 3
  • 60
  • 69
sairam
  • 11
  • 1
0

Got to this question hoping to solve this exact dilemma, and after trying what other answers propose, got to the conclusion that you just CAN'T mix methods. Either all your methods (Insert, Update, Delete) have:

  • a single custom class parameter (whose type is specified at the DataObjectTypeName attribute), or
  • a list of parameters for each of the properties (specified within each <InsertParameters>, <UpdateParameters> or <DeleteParameters>).

You can't have Insert method using the single parameter version and the Delete method using just an Int32 parameter. My findings got confirmed when I read the ObjectDataSource documentation which clearly says:

When the DataObjectTypeName property is set and the ObjectDataSource control is associated with a data-bound control, the methods that are specified by the InsertMethod and DeleteMethod properties must each have one parameter of the type that is specified in the DataObjectTypeName property.

The only exception might be the Update method which can have one or two parameters depending upon the ConflictDetection property, but that's a whole different story.

The only solution I got to was to overload the Delete method to trick the ObjectDataSource, and internally call my Delete method with the Int32 parameter:

// This method gets called by the ObjectDataSource
public Int32 Delete(MyCustomClass foo)
{
    // But internally I call the overloaded method
    Delete(foo.Id);
}

public Int32 Delete(Int32 id)
{
    // Delete the item
}
alonso.torres
  • 1,199
  • 2
  • 12
  • 26
0

In case when DataObjectTypeName is used instead of separate parameters, the business object you are using will work. You just need to add DataKeyNames="Id" where Id is the primary key field in Your Bound control like GridView or something else.

It will populate your type parameter, in your case "Employee" type with "Id" value which can be used to delete entity.

Jaswinder
  • 51
  • 14
0

The objects method signature variable names must match the objects property names exactly and it will work. eg edit* also dont forget the DataKeyNames attribute

public class EmployeeDB
{
    public int ID{get;set;}
    public string Name {get;set;}
    public ing Age{get;set;}

    //both these would work
    public void Insert(Employee emp)
    public void Insert(string Name,int Age)

    //both these would work
    public void Update(Employee emp)
    public void Update(int ID,string Name,int Age)

    //works
    public void Delete(Employee emp)

    //WONT work
    public bool Delete(int empId)
    //will work
    public void Delete(int ID)

}

<asp:ObjectDataSource 
    ID="ObjectDataSource1" 
    runat="server" 
    DataObjectTypeName="Employee"
    InsertMethod="Insert" 
    UpdateMethod="Update"
    DeleteMethod="Select" 
    TypeName="EmployeeDB" 
     DataKeyNames="ID">
<DeleteParameters>
    <asp:Parameter Name="ID" Type="Int32" />
</DeleteParameters>
</asp:ObjectDataSource>
Stuart
  • 1,227
  • 17
  • 21
0

When you bind your objectdatasource to a control, you should be able to get an Id (in your example, I would assume EmployeeId) based on the data you try to bind to, and then you can set this as a delete parameter.

check out msdn example here.

<asp:objectdatasource
          id="ObjectDataSource1"
          runat="server"
          selectmethod="GetAllEmployees"
          deletemethod="DeleteEmployee"
          ondeleting="NorthwindEmployeeDeleting"
          ondeleted="NorthwindEmployeeDeleted"
          typename="Samples.AspNet.CS.EmployeeLogic">
          <deleteparameters>
            <asp:parameter name="EmpID" type="Int32" />
          </deleteparameters>
        </asp:objectdatasource>
J.W.
  • 17,991
  • 7
  • 43
  • 76
  • When I tried that I received an error somewhere along the lines of "a delete method that takes Employee as a parameter cannot be found". Asp.Net complains if it cannot find a method with the appropriate signature. – Laz May 27 '09 at 02:03
  • You have to define this method in the code behind file. Alternativley, you can try to declare this in object data source property grid(by press F4), it will create the function signature for you. – J.W. May 27 '09 at 12:50
  • Thanks for the response, I have attempted to clarify the question above. – Laz May 27 '09 at 23:22
0

You have to remove DataObjectTypeName="Employee" from your object data source declaration. This property gets and sets the name of the class that the ObjectDataSource control uses for a parameter in your delete method.

   <asp:ObjectDataSource 
        ID="ObjectDataSource1" 
        runat="server" 
        InsertMethod="Insert" 
        UpdateMethod="Update"
        DeleteMethod="Delete" 
        TypeName="EmployeeDB">
        <deleteparameters>
            <asp:parameter name="EmpID" type="Int32" />
        </deleteparameters>
    </asp:ObjectDataSource>
Phaedrus
  • 8,351
  • 26
  • 28
  • Yes, but then I lose the ability to pass in an Employee object and have to set all of my parameters for each method. How do I use an Employee object parameter for some and not for other methods? – Laz May 27 '09 at 23:11
0

Even if you implement your class as follows:

public class EmployeeDB
{
    public Employee Insert(Employee emp)
    public Employee Update(Employee emp)
    public void Delete(Employee emp)
}

You will only get the fields bound to the 'DataKeys' passed through on the object when you try to delete, eg the ID.

*On a side note, returning the object after an Insert or Update allows the DataView to update the row.

The way I remember it working was you can configure your ObjectDataSource to pass through parameters to your db layer OR pass though the objects, NOT a combination of both.

Which means the following would be possible with the manually configured parameters:

public class EmployeeDB
{
    public int Insert(string name, DateTime dob)
    public int Update(int id, string name, DateTime dob)
    public void Delete(int id)
}
Brendan Kowitz
  • 1,795
  • 10
  • 14
0

I was using LinqToSql for a project similar to this a short while ago. I had two different types of delete methods:

    public void DeleteDisconnected(Product original_entity)
    {
        var db = new RmsConcept2DataContext(base.ConnectionString);

        db.Products.Attach(original_entity, false);

        db.Products.DeleteOnSubmit(original_entity);

        db.SubmitChanges();
    }

    public void Delete(int ID)
    {
        var db = new RmsConcept2DataContext(base.ConnectionString);

        Product product = db.Products.Single(p => p.ProductID == ID);

        // delete children
        foreach (Release release in product.Releases)
            db.Releases.DeleteOnSubmit(release);

        db.Products.DeleteOnSubmit(product);

        db.SubmitChanges();
    }

.. you can see the DeleteDisconnected method is designed to accept the whole entity object from the 'ObjectDataSource'. I was using the

ConflictDetection="CompareAllValues"

..and

OldValuesParameterFormatString="original_{0}"

..params on the 'ObjectDataSource' for this case but you may not need to do that. I think i could still get concurrency exceptions on deletes with the above approach - which is what i wanted at the time - to make use of LinqToSql's built in conflict detection/concurrency features.

Your architecture depends on how you handle data, etc in lower layers of your app (which you don't seem mention much about in the question). It is definitely more mature design to pass around the business objects rather than all the fields as method params. But occasionly (for delete functions) only the int ID is necessary.. but it depends on your underlying implementation.

Matt Kocaj
  • 11,278
  • 6
  • 51
  • 79