Livepersistence = false help

Posts   
 
    
psandler
User
Posts: 540
Joined: 22-Feb-2005
# Posted on: 10-Jul-2006 21:29:51   

Hello,

I'm trying to get 2-way databinding working with LivePersistence = false. I want to collect all of my changes in a UnitOfWork object and then persist them all at once. Currently the code only binds one entitycollection, but I'd eventually like to collect changes to multiple collections in a UOW and persist them all with one button click.

The basic problem I'm having is that as I make changes to the grid, the changes I made aren't displayed. I know why--it's because PerformSelect is being called on each update, and I refetch the collection in PerformSelect. However, if I don't refetch the collection, the entity collection on the datasource comes back empty (it doesn't seem to be saved in session?).

I'm sure I'm missing something simple.

Also: is the method I used for transferring UOW elements to another UOW object correct?

This is Northwind.

ASPX:


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Version2.WEB._Default" %>
<%@ Register Assembly="SD.LLBLGen.Pro.ORMSupportClasses.NET20" Namespace="SD.LLBLGen.Pro.ORMSupportClasses"
    TagPrefix="cc1" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button 
            ID="btnSave" 
            runat="server" 
            Text="SAVE" 
            OnClick="btnSave_Click"/>&nbsp;
        
        <cc1:LLBLGenProDataSource2 
            ID="_ordersDS" 
            CacheLocation="Session" 
            runat="server" 
            OnPerformSelect="ordersDS_PerformSelect" 
            OnPerformWork="ordersDS_PerformWork"
            AdapterTypeName="Version2.DAL.DatabaseSpecific.DataAccessAdapter, Version2.DALDBSpecific" 
            DataContainerType="EntityCollection" 
            EntityFactoryTypeName="Version2.DAL.FactoryClasses.OrdersEntityFactory, Version2.DAL" 
            LivePersistence="False">        
        </cc1:LLBLGenProDataSource2>
        
        <asp:GridView 
            ID="dgOrders" 
            runat="server" 
            DataKeyNames="OrderId" 
            DataSourceId="_ordersDS">
        <Columns>
            <asp:CommandField 
                ShowDeleteButton="true" 
                ShowCancelButton="true" 
                ShowEditButton="true"/>
        </Columns>
        </asp:GridView>
    </div>
    </form>
</body>
</html>

Code behind:


using System;
using SD.LLBLGen.Pro.ORMSupportClasses;
using Version2.DAL.EntityClasses;
using Version2.DAO;
using System.Collections.Generic;

namespace Version2.WEB
{   
    public partial class _Default : System.Web.UI.Page
    {
        CustomersEntity _customer;
        
        #region private members
        
        private string GUID
        {
            get 
            {
                if (ViewState["GUID"] == null)
                {
                    ViewState["GUID"] = Guid.NewGuid().ToString();
                }
                return (string)ViewState["GUID"];
            }
            set { ViewState["GUID"] = value; }
        }

        private UnitOfWork2 UOW
        {
            get 
            {
                if (Session[GUID + "-UOW"] == null)
                {
                    Session[GUID + "-UOW"] = new UnitOfWork2();
                }
                return (UnitOfWork2)Session[GUID + "-UOW"];
            }
            set { Session[GUID + "-UOW"] = value; }
        }

        #endregion 

        protected void ordersDS_PerformSelect(object sender, PerformSelectEventArgs2 e) 
        {
            //call to get the entity from a BL class
            _customer = FetchUtility.FetchCustomer("SAVEA");
            
            //set the entitycollection property of the DS.  The EC seems to be null before this line is hit on a postback.
            //shouldn't it be stored in session (CacheLocation)?
            //of course, now I've fetched the collection fresh from the DB, and since I haven't saved, I don't see any of 
            //my changes.
            _ordersDS.EntityCollection = _customer.Orders;  
        }

        protected void ordersDS_PerformWork(object sender, PerformWorkEventArgs2 e)
        {
            TransferUnitOfWorkElements(e.Uow, UOW);         
        }

        protected void btnSave_Click(object sender, EventArgs e)
        {
            //Commit the UOW here via a BL class.
        }
            
        //This would reside in a utility class
        //transfer the contents of one UOW to another.  
        public static void TransferUnitOfWorkElements (UnitOfWork2 source, UnitOfWork2 destination)
        {
            List<UnitOfWorkCollectionElement2> collectionElements;
            List<UnitOfWorkElement2> entityElements;

            //transfer collectionElementsToDelete
            collectionElements = source.GetCollectionElementsToDelete();
            for (int x = 0; x < collectionElements.Count; x++)
            {
                destination.AddCollectionForDelete(collectionElements[x].Collection);
            }

            //transfer collectionElementsToSave
            collectionElements = source.GetCollectionElementsToSave();
            for (int x = 0; x < collectionElements.Count; x++)
            {
                destination.AddCollectionForSave(collectionElements[x].Collection);
            }

            //transfer entities to insert
            entityElements = source.GetEntityElementsToInsert();
            for (int x = 0; x < entityElements.Count; x++)
            {
                destination.AddForSave(entityElements[x].Entity);
            }

            //transfer entities to update
            entityElements = source.GetEntityElementsToUpdate();
            for (int x = 0; x < entityElements.Count; x++)
            {
                destination.AddForSave(entityElements[x].Entity);
            }

            //transfer entities to delete
            entityElements = source.GetEntityElementsToDelete();
            for (int x = 0; x < entityElements.Count; x++)
            {
                destination.AddForDelete(entityElements[x].Entity);
            }
        }
    }
}

Thanks for any help.

Phil

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39616
Joined: 17-Aug-2003
# Posted on: 11-Jul-2006 11:50:41   

psandler wrote:

Hello,

I'm trying to get 2-way databinding working with LivePersistence = false. I want to collect all of my changes in a UnitOfWork object and then persist them all at once. Currently the code only binds one entitycollection, but I'd eventually like to collect changes to multiple collections in a UOW and persist them all with one button click.

The basic problem I'm having is that as I make changes to the grid, the changes I made aren't displayed. I know why--it's because PerformSelect is being called on each update, and I refetch the collection in PerformSelect. However, if I don't refetch the collection, the entity collection on the datasource comes back empty (it doesn't seem to be saved in session?).

The update indeed causes a refetch of the data. If you want to postpone changes made till a later date, you should use a grid which allows you to do that. Otherwise when a postback occurs and the grid calls the ExecuteUpdate method, it will also call the ExecuteSelect method, which will refetch the data, but as you've made a change to the data, it's not reflecting that change yet.

Also: is the method I used for transferring UOW elements to another UOW object correct? This is Northwind.

Looks ok. though keep in mind that if you want to postpone changes till a later date, you have to do that yourself or use a grid which makes this easy on you (i.e. has client-side editing like the devexpress grid) One thing you could do is when you get a performwork call and you don't want to save yet, you keep reference of the collection (overwriting the previous reference ofcourse) and when the performselect comes, you simply set the collection of the datasource to the collection you stored in perform work. However this is tricky I think.

Frans Bouma | Lead developer LLBLGen Pro
psandler
User
Posts: 540
Joined: 22-Feb-2005
# Posted on: 11-Jul-2006 16:48:59   

Otis wrote:

Looks ok. though keep in mind that if you want to postpone changes till a later date, you have to do that yourself or use a grid which makes this easy on you (i.e. has client-side editing like the devexpress grid) One thing you could do is when you get a performwork call and you don't want to save yet, you keep reference of the collection (overwriting the previous reference ofcourse) and when the performselect comes, you simply set the collection of the datasource to the collection you stored in perform work. However this is tricky I think.

For the moment, I am trying to avoid using a third party grid. I'd like to do this work on the server-side if possible.

I tried these steps after reading your reply:

  1. Store the Orders collection in Session in page load (only on !Postback)
  2. Use Orders from #1 as the EntityCollection of the datasource.
  3. In performwork, I set the Orders collection (stored in Session) to the Datasource's EntityCollection.

So far, this seems to work. The Orders collection (again, this is stored in Session) has a dirty entity count of 1 and the proper count (31).

Then: 4. In performselect, I set the datasource's entitycollection to the Orders collection. When it hits this code AFTER performwork, the orders collection has a count of 0.

Note that the code in #4 also gets hit on the initial page load.

I'm not clear on where the orders collection is getting reset to empty (not null?). Shouldn't the datasource's entitycollection property hold the info in session/viewstate? This is where I feel like I might be doing something wrong.

I keep the customer in session as well, so losing the reference to Customer.Orders in not the cause of the empty EntityCollection (I don't think).

I also considered making a copy of the orders collection to ensure that nothing gets messed up with references. Is this possible?

Thanks for any additional thoughts,

Phil

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39616
Joined: 17-Aug-2003
# Posted on: 12-Jul-2006 11:19:53   

psandler wrote:

Otis wrote:

Looks ok. though keep in mind that if you want to postpone changes till a later date, you have to do that yourself or use a grid which makes this easy on you (i.e. has client-side editing like the devexpress grid) One thing you could do is when you get a performwork call and you don't want to save yet, you keep reference of the collection (overwriting the previous reference ofcourse) and when the performselect comes, you simply set the collection of the datasource to the collection you stored in perform work. However this is tricky I think.

For the moment, I am trying to avoid using a third party grid. I'd like to do this work on the server-side if possible.

I tried these steps after reading your reply:

  1. Store the Orders collection in Session in page load (only on !Postback)
  2. Use Orders from #1 as the EntityCollection of the datasource.
  3. In performwork, I set the Orders collection (stored in Session) to the Datasource's EntityCollection.

So far, this seems to work. The Orders collection (again, this is stored in Session) has a dirty entity count of 1 and the proper count (31).

Then: 4. In performselect, I set the datasource's entitycollection to the Orders collection. When it hits this code AFTER performwork, the orders collection has a count of 0.

Note that the code in #4 also gets hit on the initial page load.

I'm not clear on where the orders collection is getting reset to empty (not null?). Shouldn't the datasource's entitycollection property hold the info in session/viewstate? This is where I feel like I might be doing something wrong.

It does, but when an ExecuteSelect is performed, the data is cleared and the select is done (either by internal code or by raising the PerformSelect event.

I keep the customer in session as well, so losing the reference to Customer.Orders in not the cause of the empty EntityCollection (I don't think).

I also considered making a copy of the orders collection to ensure that nothing gets messed up with references. Is this possible?

Yes, you can set the collection to use by the datasourcecontrol if you want.

Frans Bouma | Lead developer LLBLGen Pro
psandler
User
Posts: 540
Joined: 22-Feb-2005
# Posted on: 12-Jul-2006 17:38:31   

Phil wrote:

I keep the customer in session as well, so losing the reference to Customer.Orders in not the cause of the empty EntityCollection (I don't think).

I also considered making a copy of the orders collection to ensure that nothing gets messed up with references. Is this possible?

Otis wrote:

Yes, you can set the collection to use by the datasourcecontrol if you want.

I think I'm on to something. After reading this, I re-instantiated the datasource's EntityCollection at the end of perform work, and it seemed to do the trick. Since the collection will get set again in PerformSelect, there is really no reason to make a copy. It can be any entityCollection.

I will post code a little later when I get it cleaned up.

Thanks for your help Frans!