Search code examples
asp.netcruddetailsviewentitydatasource

CRUD Operations with DetailsView and EntityDataSource in Custom Server Control


I am not a big fan of ASPX pages, drag-and-drop and so on. I'm building a portal with a single Default.aspx and every other thing is custom web part controls or server controls that other developers can build in compiled dll and users can upload to the portal themselves to add features to the portal. I've been battling with DetailsView crud operations with entitydatasource. I did a test.aspx page with drag and drop and everything worked fine but with 100% code behind, nothing is. No error is displayed but data are not being persisted to database. I tried catching the onUpdating event of the detailsview and yes the event was fired and I could enumerate the data submitted but why is it not persisted to database? Hope someone can help with this.

Here's my code (trying to create everything from codebehind and add them to placeholders on the page just for testing purpose before I move everything to web part):

public partial class Test : System.Web.UI.Page
{
    private EntityDataSource eds = new EntityDataSource();       
    public DetailsView dtlview = new DetailsView();     

    protected void Page_Load(object sender, EventArgs e)
    {

        //Initialize Datasource              
        eds.ConnectionString = "name=DBEntities";
        eds.DefaultContainerName = "DBEntities";
        eds.EnableDelete = true;
        eds.EnableFlattening = false;
        eds.EnableInsert = true;
        eds.EnableUpdate = true;
        eds.EntitySetName = "EmailAccounts";            
        Controls.Add(eds);//I don't know if this is necessary           

        //Create DetailsView and configure for inserting on default
        dtlview.DataSource = eds;
        dtlview.AutoGenerateInsertButton = true;
        dtlview.AutoGenerateDeleteButton = true;
        dtlview.AutoGenerateEditButton = true;
        dtlview.AutoGenerateRows = false;
        dtlview.DefaultMode = DetailsViewMode.Insert;
        dtlview.AllowPaging = true;
        dtlview.DataKeyNames = new string[] { "ID" };
        dtlview.AllowPaging = true;

        //Create fields since autogeneraterows is false
        BoundField bfID = new BoundField();
        bfID.DataField = "ID";
        bfID.HeaderText = "ID:";
        BoundField bfUserID = new BoundField();
        bfUserID.DataField = "UserID";
        bfUserID.HeaderText = "User ID:";
        BoundField bfDisplayName = new BoundField();
        bfDisplayName.DataField = "DisplayName";
        bfDisplayName.HeaderText = "Display Name:";
        BoundField bfEmailAddress = new BoundField();
        bfEmailAddress.DataField = "EmailAddress";
        bfEmailAddress.HeaderText = "Email:";
        BoundField bfPassword = new BoundField();
        bfPassword.DataField = "Password";
        bfPassword.HeaderText = "Password:";
        BoundField bfOutgoingServer = new BoundField();
        bfOutgoingServer.DataField = "OutgoingServer";
        bfOutgoingServer.HeaderText = "Outgoing server:";
        BoundField bfIncomingServer = new BoundField();
        bfIncomingServer.DataField = "IncomingServer";
        bfIncomingServer.HeaderText = "Incoming Server:";
        CheckBoxField chkfIsDefault = new CheckBoxField();
        chkfIsDefault.DataField = "IsDefault";
        chkfIsDefault.HeaderText = "Is Default?";

        dtlview.Fields.Add(bfID);
        dtlview.Fields.Add(bfUserID);
        dtlview.Fields.Add(bfDisplayName);
        dtlview.Fields.Add(bfEmailAddress);
        dtlview.Fields.Add(bfPassword);
        dtlview.Fields.Add(bfOutgoingServer);
        dtlview.Fields.Add(bfIncomingServer);
        dtlview.Fields.Add(chkfIsDefault);

        dtlview.DataBind();

        //Events handling for detailsview
        dtlview.ItemInserting += dtlview_ItemInserting;
        dtlview.ItemInserted += dtlview_ItemInserted;
        dtlview.ModeChanging += dtlview_ModeChanging;           

        //Add controls to place holder               
        PlaceHolder2.Controls.Add(dtlview);
    }        
    protected void dtlview_ItemInserting(object sender, DetailsViewInsertEventArgs e)
    {
       e.Values["UserID"] = GetCurrentUserID();           
    }
    protected void dtlview_ItemInserted(object sender, DetailsViewInsertedEventArgs e)
    {

    }
    protected void dtlview_ModeChanging(object sender, DetailsViewModeEventArgs e)
    {
        dtlview.ChangeMode(e.NewMode);
        if (e.NewMode != DetailsViewMode.Insert)
        {
            dtlview.DataSource = eds;
            dtlview.DataBind();
        }
    }
}

Solution

  • I think what you have to do is add :

    OnContextCreating="XXXXDatasource_OnContextCreating" OnContextDisposing="XXXXDatasource_OnContextDisposing"

    To your EntityDataSource.

    Then in you code :

    protected void XXXXDatasource_OnContextCreating(object sender, EntityDataSourceContextCreatingEventArgs e)
    {
        e.Context = DBEntities.Entities;
    }
    
    protected void XXXXDatasource_OnContextDisposing(object sender, EntityDataSourceContextDisposingEventArgs e)
    {
        e.Cancel = true;
    }
    

    That way, your ObjectContext is correctly set to the EntityDataSource used by your DetailsView.

    At least that's what I read as best practice (also look up one object context per page request)