0

So I have a GridView that display loaning information, my Loans table has the ID for Laptop, User, Location, etc.

When I display on the GridView, instead I use names instead of ID numbers.

My problem is when I put a dropdownlist in the edititemtemplate such as below it does not update my table and I get the below error I want to be able to update my loans table with the appropriate info:

Cannot insert the value NULL into column 'Laptop_ID', table 'itassetmgmt.dbo.Loans'; column does not allow nulls. UPDATE fails. The statement has been terminated.

Loans Table include: Loan_ID Date_Loaned Date_Returned Sign_Off Laptop_ID User_ID Dept_ID Location_ID

ASPX:

<asp:TemplateField HeaderText="Laptop_Name" SortExpression="Laptop_Name">
            <EditItemTemplate>
                <asp:DropDownList ID="DropDownList1" SelectedValue ='<%# Bind("Laptop_Name") %>' runat="server" DataSourceID="editLPID" DataTextField="Laptop_Name" DataValueField="Laptop_Name">
                </asp:DropDownList>
                <asp:SqlDataSource ID="editLPID" runat="server" ConnectionString="<%$ ConnectionStrings:itassetmgmtConnectionString1 %>" SelectCommand="SELECT [Laptop_ID], [Laptop_Name] FROM [Laptops]"></asp:SqlDataSource>
            </EditItemTemplate>
            <ItemTemplate>
                <asp:Label ID="Label1" runat="server" Text='<%# Bind("Laptop_Name") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Name" SortExpression="Name">
            <EditItemTemplate>
                <asp:DropDownList ID="DropDownList2" runat="server" SelectedValue='<%# Bind("Name") %>' DataSourceID="editUID" DataTextField="Name" DataValueField="Name">
                </asp:DropDownList>
                <asp:SqlDataSource ID="editUID" runat="server" ConnectionString="<%$ ConnectionStrings:itassetmgmtConnectionString1 %>" SelectCommand="SELECT User_ID, Firstname +' '+ Lastname AS Name FROM Users"></asp:SqlDataSource>
            </EditItemTemplate>
            <ItemTemplate>
                <asp:Label ID="Label2" runat="server" Text='<%# Bind("Name") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Department" SortExpression="Department">
            <EditItemTemplate>
                <asp:DropDownList ID="DropDownList3" runat="server" SelectedValue='<%# Bind("Department") %>' DataSourceID="editDID" DataTextField="Department" DataValueField="Department">
                </asp:DropDownList>
                <asp:SqlDataSource ID="editDID" runat="server" ConnectionString="<%$ ConnectionStrings:itassetmgmtConnectionString1 %>" SelectCommand="SELECT * FROM [Departments]"></asp:SqlDataSource>
            </EditItemTemplate>
            <ItemTemplate>
                <asp:Label ID="Label3" runat="server" Text='<%# Bind("Department") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Location_Name" SortExpression="Location_Name">
            <EditItemTemplate>
                <asp:DropDownList ID="DropDownList4" runat="server" SelectedValue='<%# Bind("Location_Name") %>' DataSourceID="editLID" DataTextField="Location_Name" DataValueField="Location_Name">
                </asp:DropDownList>
                <asp:SqlDataSource ID="editLID" runat="server" ConnectionString="<%$ ConnectionStrings:itassetmgmtConnectionString1 %>" SelectCommand="SELECT * FROM [Locations]"></asp:SqlDataSource>
            </EditItemTemplate>
            <ItemTemplate>
                <asp:Label ID="Label4" runat="server" Text='<%# Bind("Location_Name") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>

EDIT: I know that it's probably because the DataValueField for the DropDownList isn't set to the corresponding ID# in the table, but when I change the DataValueField, it gives me a bunch of errors. Any suggestions?

My Update Command: UpdateCommand="UPDATE [Loans] SET [Date_Loaned] = @Date_Loaned, [Date_Returned] = @Date_Returned, [Sign_Off] = @Sign_Off, [Laptop_ID] = @Laptop_ID, [User_ID] = @User_ID, [Dept_ID] = @Dept_ID, [Location_ID] = @Location_ID WHERE [Loan_ID] = @original_Loan_ID"

John Saunders
  • 160,644
  • 26
  • 247
  • 397
Kristin Vernon
  • 155
  • 1
  • 2
  • 20
  • how do you fill gridview? – DanielVorph Apr 10 '15 at 17:56
  • If such `Laptop_ID` exists in the `editLPID` datasource then the most probable source of problem may be that the `SelectedValue` property is set before Items collection is populated through the `editLPID`. – Eugene Podskal Apr 10 '15 at 17:57
  • So how can I fix that? – Kristin Vernon Apr 10 '15 at 17:57
  • Honestly, I am not very proficient with ASP.NET, so I can only advise to change order of the attribute setters in the `asp:DropDownList ` to assign data source first. It may or may not help. And, before trying anything, recheck one more time with debugging that editLPID truly gives correct values and `SelectedValue='<%# Bind("Name") %>'` binds to existing column. – Eugene Podskal Apr 10 '15 at 18:03
  • Also, SqlDataSource inside template field will probably lead to multiple requests for **each** generated item. It is better to move them outside of the template. – Eugene Podskal Apr 10 '15 at 18:05
  • You may be getting a conflict due to the Name field being the same for both the Gridview and the Dropdownlist. Or, that the name provided by the gridview cannot find a match in the DropdownList set of SelectedValues. I do notice that the DDL has a `FirstName+LastName` no space between, is that so in the Gridview? – fnostro Apr 10 '15 at 18:57
  • Hey @fnostro! So it looks like that was the trick, I forgot about that space, but now my issue is it won't actually update the table because the DataValueField in the ddl is not an ID but a name – Kristin Vernon Apr 10 '15 at 19:47
  • Hey @Kristin :) Right, that's why you most always use pk's, strings get messy. You need to pass both the name AND the user ID. Display the name, and place the id in the Gridview DataKeyNames property, then Bind to the DDL SelectedValue using the user id. fill the DDL with ID/Username – fnostro Apr 10 '15 at 21:00
  • How can I accomplish that? – Kristin Vernon Apr 10 '15 at 21:25
  • putting an answer together - give me a couple of minutes – fnostro Apr 10 '15 at 21:36
  • I also added my Update Statement – Kristin Vernon Apr 10 '15 at 21:36
  • I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders Apr 10 '15 at 22:49

2 Answers2

1

In the Gridview take out all ID's from the displayable portion of the grid. No need to display them, however they must be part of the gridview datasource in order to bind against them

Then in the ItemTemplate (I'm only showing the user template) DataTextField and DataValueField come from the DropDownList datasource BUT the SelectedValue property is bound against the Gridview User_ID :

<asp:TemplateField>
  <ItemTemplate>
    <asp:DropDownList ID="DropDownList2Disabled" runat="server" DataSourceID="SqlDataSource3"
      Enabled="False" 
      DataTextField="Name" 
      DataValueField="User_ID" 
      SelectedValue='<%# Eval("User_ID") %>'>
    </asp:DropDownList>
  </ItemTemplate>
  <EditItemTemplate>
    <asp:DropDownList ID="DropDownList2" runat="server" DataSourceID="SqlDataSource3"
      DataTextField="Name" 
      DataValueField="User_ID" 
      SelectedValue='<%# Bind("User_ID") %>'>
    </asp:DropDownList>
  </EditItemTemplate>
</asp:TemplateField>

I'm using a DDL in both the ItemTemplate and EditItemTemplate, disabled in one and enabled in the other. you can use a label if you wish in the item table but that would require a bit more work as the username is not part of the gridview.

If you have control of the gridview sql and can add the username to the dataset (say as UserName) then you could bind an ItemTemplate label to the UserName and the EditItemTemplate DropDownList to the User_ID

EDIT: Expanded Example:

So, Going with the Label idea the template would look something like this:

<asp:TemplateField>
  <ItemTemplate>
    <asp:Label ID="LabelUserName" runat="server" Text='<%# Eval("UserName") %>'>
    </asp:Label>
  </ItemTemplate>
  <EditItemTemplate>
    <asp:DropDownList ID="DropDownList2" runat="server" DataSourceID="SqlDataSource3"
      DataTextField="Name" 
      DataValueField="User_ID" 
      SelectedValue='<%# Bind("User_ID") %>'>
    </asp:DropDownList>
  </EditItemTemplate>
</asp:TemplateField>

And the Gridview DataSource Select(or Stored Proc) would look (or contain) something like this:

Select Loan_ID 
    ,  l.Date_Loaned 
    ,  l.Date_Returned 
    ,  l.Sign_Off 
    ,  l.Laptop_ID 
    ,  l.User_ID 
    ,  u.FirstName + ' ' + u.LastName as UserName 
    ,  l.Dept_ID
    ,  d.DepartmentName
    ,  l.Location_ID
    ,  (etc...)
    From LoansTable l
        Left Join UserTable u on u.User_ID = l.User_ID
        Left Join DeptTable d on d.Dept_ID = l.Dept_ID
        (etc.)
    Order By d.DepartmentName
        ,    l.Date_Loaned

So this would return a fieldset that provides the Gridview with enough User Friendly Data for a clean display and also the ID's that you, the programmer, may require to make changes as the user interacts with the Gridview.

Now the ID's may or may not be added to the GridView by adding them to the DataKeyNames property. This would allow for easy access to the ID's in the code behind during GridView Postbacks. Keys placed here are not part of the displayable portion of the GridView

The DDL in the EditItemTemplate has it's own DataSource and has a simple Select:

Select User_ID, FirstName + ' ' + LastName as Name From UserTable

Do not confuse duplicate Fields from 2 different DataSources. In the EditItemTemplate the DDL Declaration:

<asp:DropDownList ID="DropDownList2" runat="server" DataSourceID="SqlDataSource3"
    DataTextField="Name" 
    DataValueField="User_ID" 
    SelectedValue='<%# Bind("User_ID") %>'>
</asp:DropDownList>

DataValueField="User_ID" refers to the DDL DataSource whereas SelectedValue='<%# Bind("User_ID") %>' is a Binding to the User_ID field in the GridView DataSource

Here the Gridview User_ID field is "hidden" from the user but available to the Gridview for editing purposes and conditionally available to you programmatically if you placed it in DataKeyNames

fnostro
  • 4,531
  • 1
  • 15
  • 23
  • So what you're saying is to include the Columns that display the ID but make them invisible and upon editing make then visible and make the columns that display name invisible? – Kristin Vernon Apr 10 '15 at 22:23
  • Close. We never really make them visible per se, just available. The Datasource makes them available, the Gridview makes them visible. I'll update my post to make things a bit more clear. – fnostro Apr 11 '15 at 08:28
0

You can use OnRowDataBound event of the Gridview:

    protected void MyGridView_RowDataBound(object sender, GridViewRowEventArgs e)
    {   
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
             if(e.Row.RowState == DataControlRowState.Edit)
             {
                  DropDownList DropDownList1 = e.Row.FindControl("DropDownList1") as DropDownList1;

                  Label Laptop_Name = e.Row.FindControl("Laptop_Name") as Label;

                //one option
                DropDownList1.SelectedValue = Laptop_Name.Text;
                //however for this option to work, when dropdownlist1 is binded data, its DataValueField should be set to "Laptop_Name"

                //second option with foreach
                foreach(ListItem item in DropDownList1.Items)
                {
                   if(item.Text == Laptop_Name.Text)
                       item.Selected = true; //not sure if the syntax is correct
                }
             }         
         }
    }

You need to change DropDownList1 definition as follows:

  <asp:DropDownList ID="DropDownList1" SelectedValue ='<%# Bind("Laptop_Id") %>' runat="server" DataSourceID="editLPID" DataTextField="Laptop_Name" DataValueField="Laptop_Id">
renakre
  • 8,001
  • 5
  • 46
  • 99
  • I get this error: Object reference not set to an instance of an object. On: DropDownList1.SelectedValue = Laptop_Name.Text; – Kristin Vernon Apr 10 '15 at 18:17
  • @KristinVernon you should do debugging to locate exactly which line cause this error – renakre Apr 10 '15 at 18:17
  • You are probably not in edit mode, so the edittemplate control is not available. Try this if (e.Row.RowState == DataControlRowState.Edit) – Adam Heeg Apr 10 '15 at 19:14
  • @KristinVernon can you see the code again, I updated it, and there is a similar example here: http://stackoverflow.com/a/14584319/1845408 – renakre Apr 10 '15 at 20:54
  • That didn't seem to work either. `Cannot insert the value NULL into column 'Laptop_ID', table 'itassetmgmt.dbo.Loans'; column does not allow nulls` – Kristin Vernon Apr 10 '15 at 21:11
  • can you specifically tell when you receive the error? The gridview is loaded fine first? and you can display each row in edit mode perfectly? – renakre Apr 10 '15 at 21:13
  • Yes this error occurs after I try to update, you see the loans table is looking for `Laptop_ID` not `Laptop_Name` – Kristin Vernon Apr 10 '15 at 21:23
  • The aspx code is what is in the question, and what's in my loans table, I added your suggested databound event (the first option because the second option gave me an error at DropDownList1.Items) but that didn't help either. But that's all the code that pertains to mi problem, I will inlcude my update statement in the question – Kristin Vernon Apr 10 '15 at 21:33
  • @KristinVernon `` – renakre Apr 10 '15 at 22:03