使用实体框架3.5在asp gridview中更新后绑定外键

时间:2014-02-06 14:01:31

标签: asp.net entity-framework

我一直试图解决这些问题。在asp gridview中使用外键创建数据绑定时,然后编辑一行并更改dropbox中的外键,保存更改并返回到查看模式(编辑行= -1),该值在国外关键列消失(除非它没有改变)。但是,如果刷新页面(不再发送数据),则会正确显示值,并按预期更改。

这也发生在继承自asp网格视图的SPGridView(sharepoint网格视图)中。

让我向您展示一个仅使用更新方法的简化示例: (我希望它不会太简化)

网格

<asp:GridView 
    ID="exampleGridView" 
    runat="server" 
    DataKeyNames="Id" 
    AutoGenerateColumns="false"
    OnRowUpdating="UpdateClick"
    OnRowDataBound="RowDataBound">
    <Columns>
        <asp:TemplateField HeaderText="Id">
            <ItemTemplate>
                <asp:Label ID="Id" runat="server" Text='<%# Bind("Id") %>' />
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Login">
            <ItemTemplate>
                <asp:Label ID="Login" runat="server" Text='<%# Bind("Login") %>' />
            </ItemTemplate>
            <EditItemTemplate>
                <asp:TextBox ID="EditLoginTextBox" runat="server" Text='<%# Bind("Login") %>' Enabled="false" />
            </EditItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Role">
            <ItemTemplate>
                <asp:Label ID="Role" runat="server" Text='<%# Bind("Role.Title") %>' />
            </ItemTemplate>
            <EditItemTemplate>
                <asp:DropDownList ID="EditRoleDropDownList" runat="server" />
            </EditItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Action">
        <ItemTemplate>
            <asp:LinkButton ID="EditLinkBtn" runat="server" CommandName="Edit" Text="edit" />
        </ItemTemplate>
        <EditItemTemplate>
            <asp:LinkButton ID="UpdateLinkBtn" runat="server" CommandName="Update" Text="update" />
        </EditItemTemplate>
    </asp:TemplateField>
    </Columns>
</asp:GridView>

背后的代码

protected void UpdateClick(object sender, System.Web.UI.WebControls.GridViewUpdateEventArgs e)
{
    // context taken from constructor, created at the beginning of a request and disposed at the end of a request
    User user = this.ctx.Users.First(u => u.Id == id);

    GridViewRow row = this.exampleGridView.Rows[e.RowIndex];

    user.Login = ((TextBox)row.FindControl("EditLoginTextBox")).Text;

    int roleId =int.Parse(((DropDownList)row.FindControl("EditRoleDropDownList")).SelectedValue);
    if (user.Role.Id != roleId)
    {
        user.Role = ctx.Attach(new Role
        {
            Id = roleId
        });
    }

    this.ctx.SaveChanges();
    this.exampleGridView.EditIndex = -1;
    this.BindGrid();
}

protected void RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow &&
        (e.Row.RowState & DataControlRowState.Edit) == DataControlRowState.Edit)
    {
        var user = (User)e.Row.DataItem;

        var editRoleDropDownList = (DropDownList)e.Row.FindControl("EditRoleDropDownList");
        this.BindRoleDropDownList(editRoleDropDownList);
        editRoleDropDownList.SelectedValue = user.Role.Id.ToString();
    }
}

private void BindGrid()
{
    this.exampleGridView.DataSource = this.ctx.Users.Include(u => u.Role);
    this.exampleGridView.DataBind();
}

private void BindRoleDropDownList(DropDownList roleDropDownList)
{
    // list of roles
    if (this.cachedRoles == null)
    {
        this.cachedRoles = this.ctx.Roles.ToList();
    }

    roleDropDownList.DataSource = this.cachedRoles;
    roleDropDownList.DataValueField = "Id";
    roleDropDownList.DataTextField = "Name";
    roleDropDownList.DataBind();
}

1 个答案:

答案 0 :(得分:0)

答案比我想象的要简单。问题在于Update方法:

int roleId = int.Parse(((DropDownList)row.FindControl("EditRoleDropDownList")).SelectedValue);
if (user.Role.Id != roleId)
{
    // this is the problem
    user.Role = ctx.Attach(new Role
    {
        Id = roleId
    });
}

问题是我用这个新对象覆盖角色,其中Role.Title显然等于空字符串。物体停留在那里。所以正确的解决方案如下:

int roleId = int.Parse(((DropDownList)row.FindControl("EditRoleDropDownList")).SelectedValue);
if (user.Role.Id != roleId)
{
    user.Role = this.ctx.Roles.First(r => r.Id == roleId);
}