How to use LivePersistence="false

Posts   
 
    
JohnRLewis avatar
JohnRLewis
User
Posts: 27
Joined: 30-Aug-2004
# Posted on: 05-May-2006 19:13:06   

I am trying to play with an Adapter template project that I just generated. I cannot figure out how to use LivePersistence="false". I can fetch the data just fine with a PerformSelect event handler. But I cannot figure out how to do the updates. The UnitOfWork property is always null. I'm using a GridView. Does anyone have a simple example of what is required to do this?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 05-May-2006 20:16:15   

The updates have to be done by a postback of the form, where you then read the UnitOfWork object from the datasourcecontrol:


    protected void Button2_Click( object sender, EventArgs e )
    {
        if( llblgenDS2.UnitOfWorkObject != null )
        {
            using( DataAccessAdapter adapter = new DataAccessAdapter() )
            {
                // persist uow
                UnitOfWork2 uow = llblgenDS2.UnitOfWorkObject;
                uow.Commit( adapter, true );
                llblgenDS2.Refetch = true;
            }
        }

    }

Frans Bouma | Lead developer LLBLGen Pro
JohnRLewis avatar
JohnRLewis
User
Posts: 27
Joined: 30-Aug-2004
# Posted on: 05-May-2006 20:20:39   

I tried that, but the UnitOfWork was always null.

Things work great if I choose LivePersistence="true", but I want to inspect the changes before I commit them.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 05-May-2006 20:41:38   

JohnRLewis wrote:

I tried that, but the UnitOfWork was always null.

Things work great if I choose LivePersistence="true", but I want to inspect the changes before I commit them.

Do you use paging? If so, if you edit something on page 1, and you then move to page 2, the data is destroyed. Is that the case in your scenario?

(edit) to elaborate a bit on this: paging using server side paging (thus paging switch on on the datasourcecontrol) loads the page of data into the contained entity collection. If the user moves to another page, the control thus loads another page of data, destroying the older page of data. It was impossible to keep track of the older pages, as that would accumulate the data in the control, because what if the user moves back and forth between pages?

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 08-May-2006 09:51:27   

I see this behavior in my testpage with filters based on selectparameters. When I edit a row, the change is made in the entity, but then the control gets a loadcomplete event which makes it gather the selectparameter values again, which cause the control to flag it's changed which means the bound controls will make a fetch, so the change is destroyed because the same data is fetched again.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 09-May-2006 10:46:59   

Fixed in next build.

Frans Bouma | Lead developer LLBLGen Pro
JohnRLewis avatar
JohnRLewis
User
Posts: 27
Joined: 30-Aug-2004
# Posted on: 10-May-2006 02:10:39   

In the May 9th build, the UnitOfWork property seems to be returning an object, but my code is still not working they way I was expecting. No records ever get updated in the database.

The code below is a simplified version of what I am trying to do in a real application. Upon selecting a record from a drop down, a FormView displays that record in Edit mode. When the user clicks Update, the database should be updated.

Please let me know if I am doing something wrong, or if the LLBLGenProDataSource2 is still exhibiting a bug.

P.S. I love llblgen!!!


<llblgen:LLBLGenProDataSource2 ID="MyDataSource1" runat="server" 
            AdapterTypeName="Boeing.CAT.BoeSysConfig.DataLayer.DatabaseSpecific.DataAccessAdapter, Boeing.CAT.BoeSysConfig.DataLayerDBSpecific"
            DataContainerType="EntityCollection"
            EntityFactoryTypeName="Boeing.CAT.BoeSysConfig.DataLayer.FactoryClasses.EthernetDNSNameEntityFactory, Boeing.CAT.BoeSysConfig.DataLayer" />
        
        <llblgen:LLBLGenProDataSource2 ID="MyDataSource2" runat="server" 
            AdapterTypeName="Boeing.CAT.BoeSysConfig.DataLayer.DatabaseSpecific.DataAccessAdapter, Boeing.CAT.BoeSysConfig.DataLayerDBSpecific"
            DataContainerType="EntityCollection"
            EntityFactoryTypeName="Boeing.CAT.BoeSysConfig.DataLayer.FactoryClasses.EthernetDNSNameEntityFactory, Boeing.CAT.BoeSysConfig.DataLayer" LivePersistence="False" OnPerformGetDbCount="MyDataSource2_PerformGetDbCount" OnPerformSelect="MyDataSource2_PerformSelect" >
            <SelectParameters>
                <asp:Parameter DefaultValue="-1" Name="EthernetDNSNameID" />
            </SelectParameters>
            
        </llblgen:LLBLGenProDataSource2>
            
        <asp:DropDownList ID="MyDropDown" runat="server" 
            DataSourceID="MyDataSource1"
            DataTextField="DNSName" 
            DataValueField="EthernetDNSNameID" 
            AutoPostBack="true"
            OnDataBound="MyDropDown_DataBound" 
            OnSelectedIndexChanged="MyDropDown_SelectedIndexChanged">
        </asp:DropDownList>
        
        <asp:FormView ID="MyFormView" runat="server" DataSourceID="MyDataSource2" DefaultMode="Edit" OnItemUpdated="MyFormView_ItemUpdated" DataKeyNames="EthernetDNSNameID">
            <EditItemTemplate>
                <asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("DNSName") %>' />
                <asp:LinkButton ID="LinkButton1" runat="server" Text="Update" CommandName="Update" />
            </EditItemTemplate>
        </asp:FormView>

protected void MyDropDown_SelectedIndexChanged(object sender, EventArgs e)
    {
        MyDataSource2.SelectParameters.Clear();
        MyDataSource2.SelectParameters.Add("EthernetDNSNameID", TypeCode.Int32, ((DropDownList)sender).SelectedValue);
        MyDataSource2.Refetch = true;
        
        MyFormView.DataBind();
    }

    protected void MyDropDown_DataBound(object sender, EventArgs e)
    {
        ((DropDownList)sender).Items.Insert(0, new ListItem("Select...", "-1"));
    }

    protected void MyDataSource2_PerformSelect(object sender, SD.LLBLGen.Pro.ORMSupportClasses.PerformSelectEventArgs2 e)
    {
        using (DataAccessAdapter da = new DataAccessAdapter())
        {
            da.FetchEntityCollection(e.ContainedCollection, e.Filter, 0, e.Sorter, e.PrefetchPath);
        }
    }
    protected void MyDataSource2_PerformGetDbCount(object sender, SD.LLBLGen.Pro.ORMSupportClasses.PerformGetDbCountEventArgs2 e)
    {
        using (DataAccessAdapter da = new DataAccessAdapter())
        {
            e.DbCount = da.GetDbCount(e.ContainedCollection, e.Filter);
        }
    }

    protected void MyFormView_ItemUpdated(object sender, FormViewUpdatedEventArgs e)
    {
        UnitOfWork2 uow = MyDataSource2.UnitOfWorkObject;
        if (uow != null)
        {
            using (DataAccessAdapter da = new DataAccessAdapter())
            {
                uow.Commit(da);
            }
        }

        MyDataSource1.Refetch = true;
        MyDropDown.DataBind();
    }
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 10-May-2006 10:20:17   

Instead of MyFormView_ItemUpdated, bind to the PerformWork event of the datasourcecontrol. You should get the data to update there. This is a new event, added to overcome problems with the live persistence and uow's.

You also don't have to set Refetch to true anymore, that's been taken care of.

Example:


<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default6.aspx.cs" Inherits="Default6" %>

<%@ Register Assembly="SD.LLBLGen.Pro.ORMSupportClasses" 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>
        <cc1:LLBLGenProDataSource2 ID="LLBLGenProDataSource2_1" runat="server" AdapterTypeName="UnitTests.Dal.Adapter.DatabaseSpecific.DataAccessAdapter, UnitTests.Dal.AdapterDBSpecific" DataContainerType="EntityCollection" EntityFactoryTypeName="UnitTests.Dal.Adapter.FactoryClasses.AddressEntityFactory, UnitTests.Dal.Adapter" LivePersistence="False" OnPerformWork="LLBLGenProDataSource2_1_PerformWork">
        </cc1:LLBLGenProDataSource2>
        <asp:FormView ID="FormView1" runat="server" DataKeyNames="AddressId" DataSourceID="LLBLGenProDataSource2_1" DefaultMode="Insert">
            <InsertItemTemplate>
                AddressId:
                <asp:TextBox ID="AddressIdTextBox" runat="server" Text='<%# Bind("AddressId") %>'></asp:TextBox><br />
                StreetName:
                <asp:TextBox ID="StreetNameTextBox" runat="server" Text='<%# Bind("StreetName") %>'></asp:TextBox><br />
                HouseNumber:
                <asp:TextBox ID="HouseNumberTextBox" runat="server" Text='<%# Bind("HouseNumber") %>'></asp:TextBox><br />
                City:
                <asp:TextBox ID="CityTextBox" runat="server" Text='<%# Bind("City") %>'></asp:TextBox><br />
                Country:
                <asp:TextBox ID="CountryTextBox" runat="server" Text='<%# Bind("Country") %>'></asp:TextBox><br />
                <asp:LinkButton ID="InsertButton" runat="server" CausesValidation="True" CommandName="Insert" Text="Insert"></asp:LinkButton>
                <asp:LinkButton ID="InsertCancelButton" runat="server" CausesValidation="False" CommandName="Cancel" Text="Cancel"></asp:LinkButton>
            </InsertItemTemplate>
            <ItemTemplate>
                AddressId:
                <asp:Label ID="AddressIdLabel" runat="server" Text='<%# Eval("AddressId") %>'></asp:Label><br />
                StreetName:
                <asp:Label ID="StreetNameLabel" runat="server" Text='<%# Bind("StreetName") %>'></asp:Label><br />
                HouseNumber:
                <asp:Label ID="HouseNumberLabel" runat="server" Text='<%# Bind("HouseNumber") %>'></asp:Label><br />
                Zipcode:
                <asp:Label ID="ZipcodeLabel" runat="server" Text='<%# Bind("Zipcode") %>'></asp:Label><br />
                City:
                <asp:Label ID="CityLabel" runat="server" Text='<%# Bind("City") %>'></asp:Label><br />
                Country:
                <asp:Label ID="CountryLabel" runat="server" Text='<%# Bind("Country") %>'></asp:Label><br />
                TestRunId:
                <asp:Label ID="TestRunIdLabel" runat="server" Text='<%# Bind("TestRunId") %>'></asp:Label><br />
                <asp:LinkButton ID="EditButton" runat="server" CausesValidation="False" CommandName="Edit" Text="Edit"></asp:LinkButton>
                <asp:LinkButton ID="DeleteButton" runat="server" CausesValidation="False" CommandName="Delete" Text="Delete"></asp:LinkButton>
                <asp:LinkButton ID="NewButton" runat="server" CausesValidation="False" CommandName="New" Text="New"></asp:LinkButton>
            </ItemTemplate>
        </asp:FormView>
    
    </div>
    </form>
</body>
</html>

codebehind:


using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using UnitTests.Dal.Adapter.DatabaseSpecific;

public partial class Default6 : System.Web.UI.Page
{
    protected void Page_Load( object sender, EventArgs e )
    {

    }

    protected void LLBLGenProDataSource2_1_PerformWork( object sender, SD.LLBLGen.Pro.ORMSupportClasses.PerformWorkEventArgs2 e )
    {
        using( DataAccessAdapter adapter = new DataAccessAdapter() )
        {
            e.Uow.Commit( adapter, true );
        }
    }
}

Frans Bouma | Lead developer LLBLGen Pro
samAdams
User
Posts: 19
Joined: 14-Nov-2005
# Posted on: 10-May-2006 14:51:28   

I'm working on the same issue and thanks for the clarification and example.

This is more of a request for advice. What would be the best approach if you are push the persist operation to a business layer that may involve transactions? With the objectdatasource you can pass the object to the business layer method specified by the DataObjectTypeName and InsertMethod properties.

With LLBLGenProDataSource2, would you pass the UnitOfWork to the business layer and manage the transaction there?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 10-May-2006 15:24:00   

If you've opted for livepersistence=false, you indeed could do that. You can also simply collect the work in a second UoW object, every time PerformWork is raised. This second UoW is then stored in the session for example. You can simply move work from one uow to another by reading the elements from one and adding the contents to the other.

Then you add a button to the page which says 'Save' and in that handler you pass the uow you used to collect work to the BL tier and use a transaction there.

Frans Bouma | Lead developer LLBLGen Pro