Link to home
Start Free TrialLog in
Avatar of metropia
metropiaFlag for United States of America

asked on

adding logging capabilities to update, insert, delete events in details view

Hello,

I am working on a web form that uses a details view.
It is functional using it without any customization.

I would like to add some logging when the user performs any crud functionality.

I would like to ask for some help, and/ or example on how to execute vb.net functions when the links on the details view are clicked.

<asp:CommandField ShowDeleteButton="True" ShowEditButton="True" ShowInsertButton="True" InsertText="Insert" UpdateText="Update" DeleteText="Delete" ButtonType="Link" />

Open in new window

Avatar of metropia
metropia
Flag of United States of America image

ASKER

I started by adding on the details view control tag:

<asp:DetailsView 
ID="dvRecipeItem" 
OnItemInserting="dvRecipeItem_ItemInserting"
OnItemInserted="dvRecipeItem_ItemInserted"
...
....

Open in new window


and then on the code behind:

   Private Sub dvRecipeItem_ItemInserted(sender As Object, e As System.Web.UI.WebControls.DetailsViewInsertedEventArgs) Handles dvRecipeItem.ItemInserted

    End Sub

    Private Sub dvRecipeItem_ItemInserting(sender As Object, e As System.Web.UI.WebControls.DetailsViewInsertEventArgs) Handles dvRecipeItem.ItemInserting
    End Sub

Open in new window


but i get an error:
BC30456: 'dvRecipeItem_ItemInserted' is not a member of 'ASP.default_aspx'.
Avatar of Jesus Rodriguez
You need to create a handler for this events on the backend code. Use on ItemCommand instead for it. Look at here

http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.detailsview.itemcommand(v=vs.110).aspx
thank you Jesus.

should it look like this then:

asp
                            OnItemCommand="DetailsViewCommandEventHandler"
                            OnItemInserting="dvRecipeItem_ItemInserting"
                            OnItemInserted="dvRecipeItem_ItemInserted"

Open in new window

code behind:
    Public Event ItemCommand As DetailsViewCommandEventHandler

    Private Sub dvRecipeItem_ItemInserted(sender As Object, e As System.Web.UI.WebControls.DetailsViewInsertedEventArgs) Handles dvRecipeItem.ItemInserted
    End Sub

    Private Sub dvRecipeItem_ItemInserting(sender As Object, e As System.Web.UI.WebControls.DetailsViewInsertEventArgs) Handles dvRecipeItem.ItemInserting

    End Sub

Open in new window

I tried also:

    OnItemCommand="dvRecipeItem_CommandEventHandler"
    OnItemInserting="dvRecipeItem_ItemInserting"
    OnItemInserted="dvRecipeItem_ItemInserted">

    Private Sub dvRecipeItem_CommandEventHandler(source As Object, e As DetailsViewCommandEventHandler)
    End Sub

    Private Sub dvRecipeItem_ItemInserted(sender As Object, e As System.Web.UI.WebControls.DetailsViewInsertedEventArgs) Handles dvRecipeItem.ItemInserted
    End Sub

    Private Sub dvRecipeItem_ItemInserting(sender As Object, e As System.Web.UI.WebControls.DetailsViewInsertEventArgs) Handles dvRecipeItem.ItemInserting
    End Sub

Open in new window


But not compiling.
Would you be able to tell me what I am missing?
Ok this works:

OnItemCommand="dvRecipeItem_ItemCommandEventHandler"

Protected Sub dvRecipeItem_ItemCommandEventHandler(sender As [Object], e As DetailsViewCommandEventArgs)

    If e.CommandName = "Insert" Then
    End If

End Sub
That's the correct way to do it. You control all the commands on the OnItemCommand Event Handler

Select Case e,CommandName
 Case "Insert"
     ' Your procedure for insert
 Case "Delete"
    'Your process for deleting
 ...
End Select


ALso you can do a small Procedure that do the log and call it like this

Public Sub RegisterFuction(Cmd as string, Rcd as String)
   'Do the process to save the User,Date and command that execute and also the record that affect where Rcd will be the Id of the affected record and Cmd the command that was executed
End Sub


and then in the OnItemCommand handler before the Case
Dim Record as string=Your Record Viewing
RegisterFunction(e.CommandName.ToString,Record)
Select Case e,CommandName
 Case "Insert"
     ' Your procedure for insert
 Case "Delete"
    'Your process for deleting
 ...
End Select
i have a question related to what i am trying to do Jesus, do you know how to access the current record on the detilas view?

I tried this:
 If Not IsNothing(Me.dvRecipeItem.Rows(0).FindControl("ItemNumber"))

But it always shows as Nothing. I think that is not how you get the value needed.

Thank you for your help.
You need to add datakeynames=[id] as an attribute to your detailsview  (id is whatever your primary key is). Like this more or less
<asp:DetailsView ID="DetailsView1" runat="server" AllowPaging="True" AutoGenerateRows="False"  DataKeyNames="DocumentID" DataSourceID="SqlDataSource1"   OnPageIndexChanged="DetailsView1_PageIndexChanged" DataMember="DefaultView">

Open in new window


and then

Dim temp as string=ItemsDetailsView.DataKey.Value.ToString()
      //or
Dim ID as string= ItemsDetailsView.DataKey(0).ToString()
I have one DataKeyNames:
DataKeyNames="Id" 

Open in new window


But I need the values of these databound fields:
<asp:BoundField DataField="ItemNumber" HeaderText="Item Number" SortExpression="ItemNumber" ApplyFormatInEditMode="True" />
<asp:BoundField DataField="ModifiedBy" HeaderText="Modified By" SortExpression="ModifiedBy" ApplyFormatInEditMode="True" />

Open in new window

Do I have to add more DataKeyNames?

Like:
DataKeyNames="Id" 
DataKeyNames="ItemNumber" 
DataKeyNames="ModifiedBy" 

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Jesus Rodriguez
Jesus Rodriguez
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Jesus,

I have been trying to make this work but I am not getting the values I need.

All am a looking right now is to obtain the value from ItemNumber, and ModifiedBy which I believe are row 1, and 4, cells 1 respectively.

Can you look at my code and tell me what I am doing wrong? Perhaps I am refering the row, cell incorrectly?

I really need to get this done :/

Any help would be great.


<Fields>
<asp:BoundField DataField="Id" HeaderText="Id" ReadOnly="True" SortExpression="Id" ApplyFormatInEditMode="True" />
<asp:BoundField DataField="ItemNumber" HeaderText="Item Number" SortExpression="ItemNumber" ApplyFormatInEditMode="True" />
<asp:BoundField DataField="VersionNumber" HeaderText="VersionNumber" SortExpression="VersionNumber" ApplyFormatInEditMode="True" />
<asp:BoundField DataField="ModifiedDateTime" HeaderText="Modified Date Time" SortExpression="ModifiedDateTime" ApplyFormatInEditMode="True" />
<asp:BoundField DataField="ModifiedBy" HeaderText="Modified By" SortExpression="ModifiedBy" ApplyFormatInEditMode="True" />

Protected Sub dvRecipeItem_ItemCommandEventHandler(sender As [Object], e As DetailsViewCommandEventArgs)

If e.CommandName = "Insert" Then
    If Not IsNothing(Me.dvRecipeItem.Rows(1).Cells(1).Text.ToString()) Then
    ' Log Insert
        Dim strItemNumber As String = Me.dvRecipeItem.Rows(1).Cells(1).Text.ToString()
        Dim strModifiedBy As String = Me.dvRecipeItem.Rows(4).Cells(1).Text.ToString()
        Dim myAppLog As New AppLogClass(inEventCode:="Recipe-Insert", inItemCode:=strItemNumber, inDetailCode:=Membership.GetUser.UserName, inDescription:="Item Inserted By: " & strModifiedBy, inNote:=strModifiedBy)
        myAppLog.Save()
    End If
End If
End Sub

Open in new window

Hello,

I think I understand what I have to do, in theory.

By declaring the DataKeyNames, I can use them to query the entity model and get the entire record, is this correct?

Dim strItemNumber As String = Me.dvRecipeItem.DataKey(1).ToString()   -- ID
Dim strModifiedBy As String = Me.dvRecipeItem.DataKey(2).ToString()      -- ItemNumber

If e.CommandName = "Update" Then
    If Not IsNothing(Me.dvRecipeItem.DataKey(1).ToString()) Then
        ' Log Update
        Dim strItemNumber As String = Me.dvRecipeItem.DataKey(1).ToString()
        Dim strModifiedBy As String = Me.dvRecipeItem.DataKey(2).ToString()
        Dim myAppLog As New AppLogClass(inEventCode:="Recipe-Update", inItemCode:=strItemNumber, inDetailCode:=Membership.GetUser.UserName, inDescription:="Item Updated By: " & strModifiedBy, inNote:=strModifiedBy)
                myAppLog.Save()
    End If
End If

Open in new window


I would like to ask for your help with the syntax of the code that queries the entity model to get the record using the DataKeys.

Would you be able to help me with this?

Thank you much
In this code that you got her
If e.CommandName = "Insert" Then
    If Not IsNothing(Me.dvRecipeItem.Rows(1).Cells(1).Text.ToString()) Then
    ' Log Insert
        Dim strItemNumber As String = Me.dvRecipeItem.Rows(1).Cells(1).Text.ToString()
        Dim strModifiedBy As String = Me.dvRecipeItem.Rows(4).Cells(1).Text.ToString()
        Dim myAppLog As New AppLogClass(inEventCode:="Recipe-Insert", inItemCode:=strItemNumber, inDetailCode:=Membership.GetUser.UserName, inDescription:="Item Inserted By: " & strModifiedBy, inNote:=strModifiedBy)
        myAppLog.Save()
    End If
End If

Open in new window


Your getting the values from different rows
Dim strItemNumber As String = Me.dvRecipeItem.Rows(1).Cells(1).Text.ToString()
Dim strModifiedBy As String = Me.dvRecipeItem.Rows(4).Cells(1).Text.ToString()

and I suppose that you want from the same row but different cell
Dim strItemNumber As String = Me.dvRecipeItem.Rows(1).Cells(1).Text.ToString()
Dim strModifiedBy As String = Me.dvRecipeItem.Rows(1).Cells(4).Text.ToString()

or no ?? Also remember that the index begins in 0 and not in 1, the first cell will have the index(0)

also as I said to you before you can get it from the displayed text like
Dim  txtMessageTitle as TextBox = TryCast(detailsViewName.FindControl("txtMessageTitle"), TextBox)  

Can you post an image of your detail view right now ??
Jesus,

This is my current code. I am not using Row, Cells anymore, I am using DataKeyNames,

I want to be able to query the entity model using the DataKey to get the record and then save it in the log table.

Thisis my idea, but it is not working so far:

Dim myContext As New OLTPEntities
Dim myRecipeRecord = myContext.RefineRecipe.Where("it.Id=" & Me.dvRecipeItem.DataKey(1).ToString()).First

'Update (log 1 row in AppLog with list of new field values in Notes field,  Example:  “ID=1, ItemNumber=12204, etc.”)

If e.CommandName = "Update" Then
    If Not IsNothing(Me.dvRecipeItem.DataKey(1).ToString()) Then
        ' Log Update
        Dim strItemNumber As String = Me.dvRecipeItem.DataKey(1).ToString()
        Dim strModifiedBy As String = Me.dvRecipeItem.DataKey(2).ToString()
        Dim myAppLog As New AppLogClass(inEventCode:="Recipe-Update", inItemCode:=strItemNumber, inDetailCode:=Membership.GetUser.UserName, inDescription:="Item Updated By: " & strModifiedBy, inNote:=myRecipeRecord.ToString())
                myAppLog.Save()
    End If
End If

Open in new window


The inNote is the column in the data table that will contain the entire record:

 inNote:=myRecipeRecord.ToString()

I am getting a message:

 Dim myRecipeRecord = myContext.RefineRecipe.Where("it.Id=" & Me.dvRecipeItem.DataKey(1).ToString()).First

 System.InvalidOperationException: Sequence contains no elements



Do you have any insight as to why this error? is my query using wrong syntax?
I modified this line:

Dim myRecipeRecord = myContext.RefineRecipe.Where("it.Id=" & Me.dvRecipeItem.DataKey(1).ToString()).First

Open in new window


to:
Dim myRecipeRecord = myContext.RefineRecipe.Where("it.Id=" & Me.dvRecipeItem.DataKey(0).ToString())

Open in new window


and the erros went away, and I am able to write to database, but the value being passed is:

System.Data.Objects.ObjectQuery`1[Recipe.RefineRecipe]

instead that the actual values.
Do a break point on this line
Dim myRecipeRecord = myContext.RefineRecipe.Where("it.Id=" & Me.dvRecipeItem.DataKey(0).ToString())

and try to Cast the values on each properties for myRecipeRecord  on the debugger to see which item returns the values
User generated imageI added FirstOrDefault after ToString:

Dim myRecipeRecord = myContext.RefineRecipe.Where("it.Id=" & Me.dvRecipeItem.DataKey(0).ToString()).FirstOrDefault()


I can see the values in the watch window. Then I get to the part that saves the record to the log table:

inNote:=myRecipeRecord.ToString()

When I go to the data table and see what got saved, I see only this:

Recipe.RefineRecipe


What happened to the values? How do I save those as a single record in the column Note?
On the Breakpoint, when the program pass over step by step, select  myRecipeRecord from the whole
Dim myRecipeRecord = myContext.RefineRecipe.Where("it.Id=" & Me.dvRecipeItem.DataKey(0).ToString()).FirstOrDefault()

and then hit Shift+F9 (quick watch) and look for the values between the properties and you will get how to cast/Trycast or diretcast your expression to get the value
I see the Recipe.RefineRecipe is:

(New System.Linq.SystemCore_EnumerableDebugView(Of Recipe.RefineRecipe)(myRecipeRecord)).Items(0)

and then every column appears as:

(New System.Linq.SystemCore_EnumerableDebugView(Of Recipe.RefineRecipe)(myRecipeRecord)).Items(0)._AgitatorEmptySpeed
(New System.Linq.SystemCore_EnumerableDebugView(Of Recipe.RefineRecipe)(myRecipeRecord)).Items(0)._BulkTankTemp

and so on.

Do I have to specify every one of the columns? I am sorry this is the first time I am working with entity framework and I am having trouble understanding it.
I think that you can specify the index only like myRecipeRecord.Items(0).Item(0) or something like that
It is not saving the record. It only saves:

Recipe.RefineRecipe