save data from formpanel to a store and then to database

Page 1 of 2 12 LastLast
  1. #1

    save data from formpanel to a store and then to database

    Hello, I m new to ext.net and I really miss the final link to save data from a formpanel to a store and then to the database.
    I have a business layer based on custom objects (basically custom collections of custom objects representing the db objects with properties and methods for crud operations and other logics process methods).
    Just as a start I was able to bind these collections to a gridpanel via store, just to see if it could work, and everything was fine.
    I did not use objectdatasource or sqldatasource to bind my custom collections to the gridpanel)

    But when I tried to insert a new record from a formpanel I went totally lost... this is the task I would accomplish:

    1) I have built a formpanel with all fields referenced to a store and all data are mapped to the reader of the store using DataIndex property; this form is used to insert a new record in the database
    2) I have a button with a listener attached, in the click event I wrote this code:
    <Listeners>
                <Click Handler="#{StoreAziendaNew}.addRecord(#{fmpnlAziendaNew}.getForm().getValues(),true, true);#{StoreAziendaNew}.save();" />  
            </Listeners>
    When I click the button there's no error, but nothing happens... the record is not saved to database, the AfterRecordInserted event of the store is not fired

    My questions are:
    when should I set the datasource for the Store i.e.:
    StoreAziendaNew.DataSource= aziendaObject
    in the codebehind?
    How can I save a record? should I intercept the client side .save() method of the Store in the codebehind, and how can I do this?

    More in general, what are the basic steps to accomplish simple CRUD operations using formpanel and store (without gridpanel)?

    I m really stuck in this step, I looked at all the examples but none seems to explain clearly how to accomplish this simple task....
    any help will be really appreciated, many thanks in advance!
    Last edited by Daniil; Feb 14, 2012 at 7:28 AM. Reason: Please use [CODE] tags
  2. #2
    Hi,

    Please investigate:
    The GridPanel/Store saving description
  3. #3

    On the way!

    Hi Daniil,

    thank you very much for pointing me out in the right direction!!
    After reading the post you suggested me, I was able to investigate the store event pipeline (a little bit complicated since it has to be in the page logic) and then decided to use an handler to submit the data, finally I could save my submitted values to the Database!!
    about this topic, I came across some other issues and doubts, that I need to clarify to go further.
    Here's the snippet code for the page and the handler:

    Handler
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Services;
    using Ext.Net;
    using xBLayer;
    using xTLayer;
    
    
    
    
    namespace testextnet
    {
        /// <summary>
        /// Summary description for $codebehindclassname$
        /// </summary>
        //[WebService(Namespace = "http://tempuri.org/")]
        //[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
        public class Save : IHttpHandler
        {
    
            public void ProcessRequest(HttpContext context)
            {
                // this is the provider for my custom typed collection
                InterlocutoriXst23CollectionProvider azprov = new InterlocutoriXst23CollectionProvider();
                // this is the typed collection; I pass the provider as parameter since it contains all the database logic 
                var azcoll = new InterlocutoriXst23Collection(azprov);
                
                //this is the typed object contained in azcoll collection
                var azienda = new InterlocutoriXst23();
                
                var sthandler = new StoreDataHandler(context);
                Response sr = new Response(true);
    
               
                ChangeRecords<InterlocutoriXst23> data = sthandler.ObjectData<InterlocutoriXst23>();
                
                 //I HAD TO COMMENT THE CONFIRMLIST HANDLING SINCE IT GIVES "object reference not set to an instance of an object" ERROR
                //ConfirmationList confirmList = sthandler.BuildConfirmationList("IdXst23");
    
                //At the moment I just check for the inserted record
                foreach (InterlocutoriXst23 az in data.Created)
                {
                    azcoll.Add(az);
                }
    
                azcoll.SaveCollection();
    
                 //HAD TO COMMENT THIS ONE AS WELL
                //foreach (InterlocutoriXst23 az in data.Created)
                //{
                //    confirmList[azienda.IdXst23.ToString()].ConfirmRecord(azienda.IdXst23.ToString());
                //}
    
    
                StoreResponseData response = new StoreResponseData();
                 
                 //ALWAYS COMMENTED FOR THE CONFIRMLIST ISSUE
                //response.Confirmation = confirmList;
    
                sr.Data = response.ToString();
                
            }
    
            public bool IsReusable
            {
                get
                {
                    return false;
                }
            }
        }
    }
    page

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="aziendanew.aspx.cs" Inherits="testextnet.aziendanew" %>
    <%@ Register assembly="Ext.Net" namespace="Ext.Net" tagprefix="ext" %>
    
    <script runat="server">
    protected void btnNext_Click(object sender, DirectEventArgs e)
            {
     
                int index = int.Parse(e.ExtraParams["index"]);
    
                if ((index + 1) < this.crdpanel.Items.Count)
                {
                    this.crdpanel.ActiveIndex = index + 1;
                }
    
    
            }
    </script>
    
    
    <!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>Nuova azienda</title>
    </head>
    <body>
        <form id="form1" runat="server">
        <ext:ResourceManager ID="ResourceManager1" runat="server" />
     <ext:Store 
            runat="server" 
            ID="StoreAziendaNew" 
            OnAfterRecordInserted="StoreAziendaNew_AfterRecordInserted" 
            OnBeforeRecordInserted="StoreAziendaNew_BeforeRecordInserted"
            OnAfterStoreChanged="StoreAziendaNew_AfterStoreChanged">
            <Reader>
                <ext:JsonReader IDProperty="IdXst23">
                     <Fields>
                        <ext:RecordField Name="IdXst23" IsComplex="true" ServerMapping="IdXst23.Value" />
                        <ext:RecordField Name="CognomeRagSocXst23" IsComplex="true" ServerMapping="CognomeRagSocXst23.Value"/>
                        <ext:RecordField Name="CodFiscale1Xst23" IsComplex="true" ServerMapping="CodFiscale1Xst23.Value"/>
                        <ext:RecordField Name="FlagPersonaFisicaXst23" DefaultValue="'G'" IsComplex="true" ServerMapping="FlagPersonaFisicaXst23.Value"/>
                        <ext:RecordField Name="IdXst01NaturaGiuridicaXst23" IsComplex="true" ServerMapping="IdXst01NaturaGiuridicaXst23.Value"/>
                        <ext:RecordField Name="IdXst01SessoXst23" IsComplex="true" ServerMapping="IdXst01SessoXst23.Value"/>
                        <ext:RecordField Name="IdXst21ComuneNascitaXst23" IsComplex="true" ServerMapping="IdXst21ComuneNascitaXst23.Value"/>
                        <ext:RecordField Name="IdXst21NazioneXst23" IsComplex="true" UseNull="true" ServerMapping="IdXst21NazioneXst23.Value"/>
                        <ext:RecordField Name="IdXst21ComunePif11" IsComplex="true" ServerMapping="IdXst21ComunePif11.Value"/>
                        <ext:RecordField Name="IdXst23RappLegaleXst23" IsComplex="true" ServerMapping="IdXst23RappLegaleXst23.Value"/>
                        <ext:RecordField Name="DescrizioneXst23" IsComplex="true" ServerMapping="DescrizioneXst23.Value"/>
                        <ext:RecordField Name="AutDiffusioneXst23" IsComplex="true" DefaultValue="true" ServerMapping="AutDiffusioneXst23.Value"/>
                      </Fields>
                </ext:JsonReader>
            </Reader>
            <Listeners>
            <Added Handler="alert('record aggiunto');" />
            <SaveException Handler="alert('salvataggio fallito');" />
            </Listeners>
            <UpdateProxy>
            <ext:HttpWriteProxy Method="POST" Url="Save.ashx" />
            </UpdateProxy>
        </ext:Store>
        <ext:Store runat="server" ID="StoreSediAziendanew">
            <Reader>
                <ext:JsonReader IDProperty="IdXst26">
                    <Fields>
                        <ext:RecordField Name="IdXst26" IsComplex="true" ServerMapping="IdXst26.Value"/>
                        <ext:RecordField Name="IdXst21ComuneXst26" IsComplex="true" ServerMapping="IdXst21ComuneXst26.Value"/>
                        <ext:RecordField Name="IndirizzoXst26" IsComplex="true" ServerMapping="IndirizzoXst26.Value"/>
                        <ext:RecordField Name="LocalitaXst26" IsComplex="true" ServerMapping="LocalitaXst26.Value"/>
                        <ext:RecordField Name="TelFissoXst26" IsComplex="true" ServerMapping="TelFissoXst26.Value"/>
                        <ext:RecordField Name="TelMobileXst26" IsComplex="true" ServerMapping="TelMobileXst26.Value"/>
                        <ext:RecordField Name="FaxXst26" IsComplex="true" ServerMapping="FaxXst26.Value"/>
                        <ext:RecordField Name="EmailXst26" IsComplex="true" UseNull="true" ServerMapping="EmailXst26.Value"/>
                    </Fields>
                </ext:JsonReader>
            </Reader>
        </ext:Store>
        <ext:Store runat="server" ID="StorePersonaNew" />
        <ext:Store runat="server" ID="StoreIndirizzoPersonaNew" />
     <ext:FormPanel 
            ID="fmpnlAziendaNew" 
            runat="server" 
            Closable="false" 
            Draggable="false"  
            LabelAlign="Top"
            Frame="false"
            Border="false"
            Padding="5"
            Header="false"
            BodyStyle="background-color:#ffffff" AnchorHorizontal="100%"
            Layout="FormLayout">
            <Items>
            <ext:Container ID="Container1" runat="server" Layout="Column" Height="220">
            <Items>
             <ext:Container ID="Container2" runat="server" LabelAlign="Top" Layout="FitLayout" ColumnWidth=".5">
                <Items>
            <ext:Panel runat="server" Border="false" FormGroup="true" Title="DATI AZIENDA" Collapsible="true" Layout="FormLayout" >
            <Items>
                    <ext:Hidden runat="server" ID="IdXst23" DataIndex="IdXst23" />
                    <ext:TextField 
                        runat="server" 
                        ID="txtRagioneSociale"
                        AnchorHorizontal="50%"
                        FieldLabel="Denominazione" 
                        DataIndex="CognomeRagSocXst23" 
                        AllowBlank="false" 
                        IndicatorIcon="BulletRed" 
                        IndicatorTip="Campo obbligatorio" 
                        BlankText="Ragione sociale obbligatoria" 
                        MsgTarget="Side"
                        IsFormField="true" />
                    <ext:TextField 
                        runat="server" 
                        ID="txtPiva"
                        AnchorHorizontal="50%"
                        FieldLabel="Partita IVA" 
                        DataIndex="CodFiscale1Xst23" 
                        AllowBlank="false" 
                        IndicatorIcon="BulletRed" 
                        IndicatorTip="Campo obbligatorio" 
                        BlankText="Partita IVA obbligatoria" 
                        MsgTarget="Side"
                        IsFormField="true"
                        Regex="^[0-9]{11}$"
                        RegexText="Partita IVA non valida" 
                        MaxLength="11"
                        Icon="DatabaseConnect"/>                                
            </Items>
            </ext:Panel>
            </Items>
            </ext:Container>
             <ext:Container ID="Container3" runat="server" LabelAlign="Top" Layout="FitLayout" ColumnWidth=".5">
                <Items>
            <ext:Panel ID="Panel1" runat="server" Border="false" FormGroup="true" Title="RIFERIMENTI" Collapsible="true" Layout="FormLayout" >
            <Items>
                  <ext:TextField 
                    runat="server" 
                    ID="txtNrTelefono"
                    AnchorHorizontal="50%"
                    FieldLabel="Numero di telefono" 
                    DataIndex="TelFissoXst26" 
                    AllowBlank="false" 
                    IndicatorIcon="BulletRed"                 
                    IndicatorTip="Campo obbligatorio" 
                    BlankText="numero di telefono obbligatorio" 
                    MsgTarget="Side"
                    IsFormField="true" />
                  <ext:TextField 
                    runat="server" 
                    ID="txtNrCellulare"
                    AnchorHorizontal="50%"
                    FieldLabel="Numero cellulare" 
                    DataIndex="TelMobileXst26" 
                    AllowBlank="false" 
                    IndicatorIcon="BulletRed" 
                    IndicatorTip="Campo obbligatorio" 
                    BlankText="numero di cellulare obbligatorio" 
                    MsgTarget="Side"
                    IsFormField="true"
                    />
                  <ext:TextField 
                    runat="server" 
                    ID="txtFax"
                    AnchorHorizontal="50%"
                    FieldLabel="Numero Fax" 
                    DataIndex="FaxXst26" 
                    AllowBlank="false" 
                    IndicatorIcon="BulletRed" 
                    IndicatorTip="Campo obbligatorio" 
                    BlankText="numero di fax obbligatorio" 
                    MsgTarget="Side"
                    IsFormField="true"
                    />
                   <ext:TextField
                        runat="server"
                        ID="txtEmail"
                        AllowBlank="true"
                        DataIndex="EmailXst26"
                        FieldLabel="e-mail"
                        AnchorHorizontal="50%"
                        Vtype="email" />
            </Items>
            </ext:Panel>
            </Items>
            </ext:Container>
            </Items>
            </ext:Container>
            <ext:TextArea runat="server" AnchorHorizontal="100%" ID="txtDescrizione" FieldLabel="Descrizione Azienda" />
             <ext:Container ID="Container4" runat="server" Layout="FitLayout" Height="180">
                <Items>
                    <ext:Panel ID="pnlSedeAzienda" runat="server" FormGroup="true" Layout="FormLayout" Title="Sede Azienda">
                        <Items>
                            <ext:TextField 
                                runat="server" 
                                ID="txtComune" 
                                AnchorHorizontal="50%" 
                                FieldLabel="Comune"/>
                            <ext:TextField 
                                runat="server" 
                                ID="txtIndirizzo" 
                                AnchorHorizontal="80%" 
                                FieldLabel="Indirizzo"/>
                            <ext:ComboBox
                                ID="cbComuniSabina"
                                runat="server"
                                FieldLabel="Comune sede legale"
                                DataIndex="IdXst21ComuneXst26"
                                ValueField="IdXst21"
                                DisplayField="Comune">
                                <Store>
                                <ext:Store runat="server" ID="storeComuniSabina">
                                    <Reader>
                                        <ext:JsonReader IDProperty="IdXst21">
                                            <Fields>
                                                 <ext:RecordField Name="IdXst21" IsComplex="true" ServerMapping="IdXst21.Value"/>
                                                 <ext:RecordField Name="Comune" IsComplex="true" ServerMapping="Comune.Value"/>
                                            </Fields>
                                        </ext:JsonReader>
                                    </Reader>
                                </ext:Store>
                                </Store>
                                </ext:ComboBox>
                        </Items>
                    </ext:Panel>
                    <ext:Panel runat="server" AnchorHorizontal="100%" ID="pnlRapprLegale" FormGroup="true" Layout="FormLayout" Title="LEGALE RAPPRESENTANTE">
                        <Items>
                            <ext:TextField runat="server" ID="txtCFisc" AllowBlank="false" AnchorHorizontal="80%" FieldLabel="Codice Fiscale" />
                            <ext:CompositeField runat="server" ID="cmpNome" AnchorHorizontal="100%">
                                <Items>
                                    <ext:TextField runat="server" ID="txtNome" AnchorHorizontal="80%" FieldLabel="Nome" Flex="1" />
                                    <ext:TextField runat="server" ID="txtCognome" AnchorHorizontal="80%" FieldLabel="Cognome" Flex="1" />
                                </Items>
                            </ext:CompositeField>
                            <ext:DateField runat="server" ID="txtDataNascita" FieldLabel="Data di Nascita" Format="dd/m/yyyy" />
                            <ext:TextField runat="server" ID="txtLuogoNascita" FieldLabel="Luogo di nascita" />
                            <ext:TextField runat="server" ID="txtComuneResidenza" FieldLabel="Comune di residenza" />
                            <ext:TextField runat="server" ID="txtIndirizzoResidenza" FieldLabel="Indirizzo di residenza" />
                        </Items>
                    </ext:Panel>
                </Items>
             </ext:Container>
    
        </Items>
        
        <Buttons>
        <ext:Button runat="server" ID="btnNext" Text="Salva e prosegui" Icon="Disk" Type="Submit" >
        <DirectEvents>
        <Click OnEvent="btnNext_Click">
            <ExtraParams>
                <ext:Parameter Name="index" Value="#{crdpanel}.items.indexOf(#{crdpanel}.layout.activeItem)" Mode="Raw" />
                <ext:Parameter Name="Data" Value="#{fmpnlAziendaNew}.getForm().getValues()" Mode="Raw" Encode="true" />
            </ExtraParams>
        </Click>
        </DirectEvents>
            <Listeners>
                <%--<Click Handler="#{StoreAziendaNew}.addRecord(#{fmpnlAziendaNew}.getForm().getValues(),true, true);#{StoreAziendaNew}.save();" />--%>  
                <Click Handler="#{StoreAziendaNew}.insertRecord(0);#{fmpnlAziendaNew}.getForm().updateRecord(#{StoreAziendaNew}.getAt(0));#{StoreAziendaNew}.save();" />
            </Listeners>
            
        </ext:Button>
        </Buttons>
        
        </ext:FormPanel>
    
        </form>
    </body>
    </html>
    I came across the following issues:

    1. In the handler I mapped the Id for the ConfirmationList on "IdXst23" field; the column is related to the store's reader? By the way, i mapped an hidden field to the reader's column and tried to assign even a default value but this element was always null when i posted data to the handler; I had to comment the BuildConfirmList since it throws an "object reference not set to an instance of an object" exception
    2. After the idConfirmation issue, I commented every related code to see if i could correctly save to the db (the tables have all an Identity key column); it worked but after the debugger returns me to the page these errors appear (image attached) (they are caught by the <saveexception> tag of the store). How should be the confirmationlist handled? did I set the uncorrect mapping?
    3. Since the values to save to Db are in different tables, I would be able to use the data from different stores using a unique handler; you see two stores in the page code; one is related to the company reference, the other to the company location; these are in different table in the DB. If I use the same handler for the company location Store, will it work, of course implementing the related logic?


    I was a bit too long....
    Thanks again for your help :)
    Attached Thumbnails Click image for larger version. 

Name:	error.gif 
Views:	339 
Size:	93.2 KB 
ID:	3827  
  4. #4
    The following example demonstrates how to save a data using HttpHandler with Confirmation.
    https://examples1.ext.net/#/GridPane.../Confirmation/

    Hope this helps.
  5. #5
    Thanks Daniil,
    I investigated that example and I refined my test code, so I got the problem, it seems to be a JSON Serialization error.
    When debug this row:

                InterlocutoriXst23CollectionProvider azprov = new InterlocutoriXst23CollectionProvider();
                var azcoll = new InterlocutoriXst23Collection(azprov);
                            
                var sthandler = new StoreDataHandler(context);
                Response sr = new Response(true);
                ChangeRecords<InterlocutoriXst23> data = sthandler.ObjectData<InterlocutoriXst23>();
    the ChangeRecords Object is correctly populated, but the Id is null.

    In the ConfirmList I can see the oldValue = -1, so it works properly, since I used UseIdConfirmation.
    ConfirmationList confirmList = sthandler.BuildConfirmationList("IdXst23.Value");
    I investigated further and found a post about the UseIdConfirmation where is explained how the id column is managed from the reader, if it is present in the records list or not:

    http://forums.ext.net/showthread.php...IdConfirmation

    So the picture is more clear, however, if the Store has the following setting, the handler.BuildConfirmation code throws JSON serialization Exception:
    "cannot convert -1 to Nulltype.IntNT".
    IntNT is a custom nullable type representing the properties of the custom object, but it does support negative integers.

     <ext:Store 
            runat="server" 
            ID="StoreAziendaNew" 
            OnAfterRecordInserted="StoreAziendaNew_AfterRecordInserted" 
            OnBeforeRecordInserted="StoreAziendaNew_BeforeRecordInserted"
            OnAfterStoreChanged="StoreAziendaNew_AfterStoreChanged" UseIdConfirmation="true">
            <Reader>
                 <ext:JsonReader IDProperty="IdXst23.Value">
                     <Fields>
                        <%--<ext:RecordField Name="IdXst23" IsComplex="true" ServerMapping="IdXst23.Value"/>--%>
                        <ext:RecordField Name="CognomeRagSocXst23" IsComplex="true" ServerMapping="CognomeRagSocXst23.Value"/>
                        <ext:RecordField Name="CodFiscale1Xst23" IsComplex="true" ServerMapping="CodFiscale1Xst23.Value"/>
                        <ext:RecordField Name="FlagPersonaFisicaXst23" DefaultValue="'G'" IsComplex="true" ServerMapping="FlagPersonaFisicaXst23.Value"/>
                        <ext:RecordField Name="IdXst01NaturaGiuridicaXst23" IsComplex="true" ServerMapping="IdXst01NaturaGiuridicaXst23.Value"/>
                        <ext:RecordField Name="IdXst01SessoXst23" IsComplex="true" ServerMapping="IdXst01SessoXst23.Value"/>
                        <ext:RecordField Name="IdXst21ComuneNascitaXst23" IsComplex="true" ServerMapping="IdXst21ComuneNascitaXst23.Value"/>
                        <ext:RecordField Name="IdXst21NazioneXst23" IsComplex="true" UseNull="true" ServerMapping="IdXst21NazioneXst23.Value"/>
                        <ext:RecordField Name="IdXst21ComunePif11" IsComplex="true" ServerMapping="IdXst21ComunePif11.Value"/>
                        <ext:RecordField Name="IdXst23RappLegaleXst23" IsComplex="true" ServerMapping="IdXst23RappLegaleXst23.Value"/>
                        <ext:RecordField Name="DescrizioneXst23" IsComplex="true" ServerMapping="DescrizioneXst23.Value"/>
                        <ext:RecordField Name="AutDiffusioneXst23" IsComplex="true" DefaultValue="true" ServerMapping="AutDiffusioneXst23.Value"/>
                      </Fields>
                </ext:JsonReader>
            </Reader>
    If uncomment the field with the IdXst23 as record field exception doesn't raise, because empty value is cast to null from nullable type, but the id is not assigned to the idproperty of the created record, so I have a record with IdXst23 null.
    confirmlist values and created record don't match (confirmlist has id -1 and record has id null), and record confirmation can't be implemented as in the sample.
    Is JSON serialization possible for nullable types?
  6. #6
    Quote Originally Posted by lapix View Post
    Is JSON serialization possible for nullable types?
    I would answer it yes, because the following code doesn't cause any error:
    Nullable<int> test = -1;
    string json = JSON.Serialize(test);
    test = JSON.Deserialize<Nullable<int>>(json);
    Regarding to the problem.

    I think you need replace
    IDProperty="IdXst23.Value"
    with
    IDProperty="IdXst23"
    Hope this helps.

    Also do you really need IsComplex for all fields? What is the "IdXst23.Value" and others?
  7. #7
    Thanks for the suggestion, but I already tried that and the result is the JSON serialization exception (see image attached).
    I m not sure if IsComplex is needed or not, since I m not sure about its purpose; I thought it was useful for binding with objects with more properties whose values are not immediate to catch from the reader.
    the IdXst23.Value and others are the properties I mapped for my custom nullable types (in the specific xTLayer.NullTypes.IntNT) that are the type of the "fields of my custom objects and collection.
    The reason is.... inheritance; these Business Logic Libraries were built before the 2.0 framework introduced nullable types....
    This choice comes from my first experiment in binding a gridpanel with my custom collections, since otherwise data were not displayed in the grid.

    anyway the handler shows that data are there (i step in the innerxml data of the created records array):

    <records>
    <Created>
     <record>
      <CognomeRagSocXst23>ditta prova</CognomeRagSocXst23> 
      <CodFiscale1Xst23>12121212121</CodFiscale1Xst23> 
      <FlagPersonaFisicaXst23>G</FlagPersonaFisicaXst23> 
      <IdXst01NaturaGiuridicaXst23 /> 
      <IdXst01SessoXst23 /> 
      <IdXst21ComuneNascitaXst23 /> 
      <IdXst21NazioneXst23 /> 
      <IdXst21ComunePif11 /> 
      <IdXst23RappLegaleXst23 /> 
      <DescrizioneXst23 /> 
      <AutDiffusioneXst23>true</AutDiffusioneXst23> 
      <IdXst23>-1</IdXst23> 
     </record>
     </Created>
     </records>
    As you correctly noted, if I leave IdXst23.Value, exception is not raised and everything goes to completion, but inspecting the ChangeRecords collection:

    ChangeRecords<InterlocutoriXst23> data = handlerAzienda.ObjectData<InterlocutoriXst23>();
    the new record is present with all the data, except for the IdXst23 value, which is null... is it a normal behaviour? shoudn't I see the -1 generated value for this property?
    Since I don't have binding with the id, the following confirmation steps are compromised..
    Thanks again for your patience, Daniil.
    Attached Thumbnails Click image for larger version. 

Name:	json_exception.jpg 
Views:	238 
Size:	94.7 KB 
ID:	3831  
  8. #8
    IsComplex might help if you need to render a property as a complex object.

    For example, imagine the following data:
    store.DataSource = new object[] 
    { 
        new 
        {
            TestSimple = "test simple",
            TestComplex = new
            {
                foo = "foo",
                bar = "bar"   
            }   
        }
    };
    The TestSimple property will be rendered to client as the string "test simple", there is no problem.

    But TestComplex won't be rendered to client with this simple RecordField:
    <ext:RecordField Name="TestComplex" />
    But if you set up IsComplex="true":
    <ext:RecordField Name="TestComplex" IsComplex="true" />
    then the object (the value of TestComplex) will be serialized and rendered to client.

    Then you could parse that object on client side within RecordField's Convert.

    The ServerMapping is an alternative solution and it doesn't require IsComplex.

    The TestComplex property might be parsed on server side setting up respective ServerMapping.
    <ext:RecordField Name="TestComplexFoo" ServerMapping="TestComplex.foo" />
    <ext:RecordField Name="TestComplexBar" ServerMapping="TestComplex.bar" />
    Here is a full example.

    Example
    <%@ Page Language="C#" %>
     
    <%@ Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
    
    <script runat="server">
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!X.IsAjaxRequest)
            {
                Store store = this.GridPanel1.GetStore();
                store.DataSource = new object[] 
                { 
                    new 
                    {
                        TestSimple = "test simple",
                        TestComplex = new
                        {
                            foo = "foo",
                            bar = "bar"   
                        }   
                    }
                };
                store.DataBind();
            }
        }
    </script>
    
    <!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>Ext.NET Example</title>
    </head>
    <body>
        <form runat="server">
            <ext:ResourceManager runat="server" />
            <ext:GridPanel 
                ID="GridPanel1" 
                runat="server" 
                AutoHeight="true">
                <Store>
                    <ext:Store runat="server">
                        <Reader>
                            <ext:JsonReader>
                                <Fields>
                                    <ext:RecordField Name="TestSimple" />
                                    <ext:RecordField Name="TestComplex" IsComplex="true" />
                                    <ext:RecordField Name="TestComplexFoo" ServerMapping="TestComplex.foo" />
                                    <ext:RecordField Name="TestComplexBar" ServerMapping="TestComplex.bar" />
                                </Fields>
                            </ext:JsonReader>
                        </Reader>
                    </ext:Store>
                </Store>
                <ColumnModel runat="server">
                    <Columns>
                        <ext:Column Header="TestSimple" DataIndex="TestSimple" />
                        <ext:Column Header="TestComplex" DataIndex="TestComplex" />
                        <ext:Column Header="TestComplexFoo" DataIndex="TestComplexFoo" />
                        <ext:Column Header="TestComplexBar" DataIndex="TestComplexBar" />
                    </Columns>
                </ColumnModel>
            </ext:GridPanel>
        </form>
    </body>
    </html>
    So, I guess you could remove IsComplex of all RecordFields, though, I'm not 100% what objects you bind to the Store.


    Regarding to the problem with ids.

    Generally, I think you should not use Nullable type as a source of records ids, I mean the IDProperty.

    As far as I can understand IdXst23 might have "null" value, right? If yes, I think, it's not appropriate to be IDProperty, i.e. a record's id.

    If it can't have a "null" value, then you can use it as IDProperty for sure.

    But then, as you said, the exception occurs on the
    ChangeRecords<InterlocutoriXst23> data = handlerAzienda.ObjectData<InterlocutoriXst23>();
    stage.

    What is the "xTLayer.NullTypes.IntNT" type? I mean its definition. I would try to reproduce the problem.
  9. #9
    Hi Daniil,
    thanks for your explanation about the isComplex property; I removed it from the recordfield definition, and the ServerMapping alone is working without problems.
    About the intNT type and the objects I bind to the Store, i will try to explain you better what kind of classes i work with and the id null issue.

    here is a definition for the xTLayer.NullTypes.intNT Type:

    using System;
    using System.IO;
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Binary;
    
    namespace xTLayer
    {
        namespace Nulltypes
        {
    
            public class NullType : IComparable, IFormattable
            {
                protected object _value;
    
                /// <summary>
                /// IComparable.CompareTo implementation.
                /// </summary>
                public int CompareTo(object obj)
                {
                    if (obj is NullType)
                    {
                        NullType temp = (NullType)obj;
    
                        return compare(this, temp);
                    }
                    throw new ArgumentException("object is not a NullType");
                }
                public static bool IsReallyNull(NullType n)
                {
                    return (((object)n) == null || n._value == null);
                }
                private static System.Collections.Comparer _Comparer = new System.Collections.Comparer(System.Globalization.CultureInfo.CurrentCulture);
                protected static int compare(NullType a, NullType b)
                {
                    if (!isNull(a) && isNull(b))
                        return 1;
    
                    if (isNull(a) && !isNull(b))
                        return -1;
    
                    if (isNull(a) && isNull(b))
                        return 0;
                    return _Comparer.Compare(a._value, b._value);
                }
                protected static bool isNull(NullType a)
                {
                    return (object)a == null || a._value == null || a._value.ToString() == "";
                }
    
                //public bool isNull {get { return _value == null;} set { if (value) _value = null; }}
    
                public NullType()
                {
                    _value = null;
                }
                public override int GetHashCode()
                {
                    if (_value != null) return _value.GetHashCode();
                    return base.GetHashCode();
    
                }
                public static bool operator ==(NullType nt, NullType o)
                {
                    return compare(nt, o) == 0;
                }
                public static bool operator !=(NullType nt, NullType o)
                {
                    return compare(nt, o) != 0;
                    //return !(pi == o);
                }
    
                public static bool operator <(NullType nt, NullType o)
                {
                    return compare(nt, o) < 0;
                }
    
                public static bool operator >(NullType nt, NullType o)
                {
                    return compare(nt, o) > 0;
                }
    
                public static bool operator <=(NullType nt, NullType o)
                {
                    return compare(nt, o) <= 0;
                }
    
                public static bool operator >=(NullType nt, NullType o)
                {
                    return compare(nt, o) >= 0;
                }
    
                //		public static bool IsNull(NullType pi)
                //		{
                //			return (((object)pi == null) || (pi.isNull)) ? true : false;
                //		}
                //		public static bool IsNull(object pi)
                //		{
                //			return (((object)pi == null) || (pi is System.DBNull) ) ? true : false;
                //		}
    
                public static bool operator ==(NullType pi, object o)
                {
                    try
                    {
                        // null null true
                        // null val false
                        // val null false
                        // val val confronto
                        if (((object)pi == null) || pi._value == null)
                        {
                            return ((o == null) || Convert.IsDBNull(o));
                        }
                        return ((o == null) || Convert.IsDBNull(o)) ? false : System.Convert.Equals(pi._value, o);
                    }
                    catch
                    {
                        return false;
                    }
                }
                public override bool Equals(object o)
                {
                    if (o is NullType) return (this == (NullType)o);
                    else return (this == o);
                }
    
                public static bool operator !=(NullType pi, object o)
                {
                    return !(pi == o);
                }
    
                /// <summary>
                /// fa l'override del ToString. Se è nullo ritorna "" altrimenti passa al tostring del valore contenuto.
                /// </summary>
                /// <returns></returns>
                public override string ToString()
                {
                    return this == null ? "" : _value.ToString();
                }
    
                public static implicit operator string(NullType nt)
                {
                    return nt == null ? "" : nt._value.ToString();
                }
    
    
                /*public Object ObjectValue 
                {
                    get 
                    { 
                        return _value;
                    } 
    				
                }*/
    
                #region IFormattable Members
    
                string System.IFormattable.ToString(string format, IFormatProvider formatProvider)
                {
                    return _value == null ? "" : ((System.IFormattable)_value).ToString(format, formatProvider);
                }
    
                #endregion
            }
            public class IntNT : NullType, ISerializable, System.Xml.Serialization.IXmlSerializable, IFormattable
            {
                #region IXmlSerializable
                public void WriteXml(System.Xml.XmlWriter writer)
                {
                    if (_value != null)
                        writer.WriteString(this.ToString());
                    else writer.WriteAttributeString("null", "true");
                }
    
                public void ReadXml(System.Xml.XmlReader reader)
                {
                    //if (reader.GetAttribute("null")!="true") //	if (reader.HasValue)
                    if (reader.HasAttributes) // se ha attributi è nullo.
                        _value = null;
                    else
                    {
                        string str = reader.ReadString();
                        if (IsInt(str)) _value = Convert.ToInt32(str);
                    }
                    reader.ReadEndElement();
                }
    
                public System.Xml.Schema.XmlSchema GetSchema()
                {
                    return (null);
                }
                #endregion
    
                #region Serializable
                public void GetObjectData(SerializationInfo info, StreamingContext context)
                {
                    if (_value != null)
                        info.AddValue("_value", Value);
                }
    
                private IntNT(SerializationInfo info, StreamingContext context)
                {
                    if (info.MemberCount == 1)
                    {
                        _value = info.GetInt32("_value");
                    }
                    else _value = null;
                }
                #endregion
                /// <summary>
                /// IntNT nullo
                /// </summary>
                public IntNT()
                {
                    _value = null;
                }
                /// <summary>
                /// costruttore 
                /// </summary>
                /// <param name="valore"></param>
                public IntNT(object valore)
                {
                    if (valore is IntNT)
                    {
                        _value = ((IntNT)valore)._value;
                        return;
                    }
                    if (null == valore || Convert.IsDBNull(valore) || valore.ToString() == "")
                        _value = null;
                    else
                        _value = Convert.ToInt32(valore);
                }
    
                /// <summary>
                /// costruttore di copia
                /// </summary>
                /// <param name="IntNTObj"></param>
                public IntNT(IntNT IntNTObj)
                {
                    if (null == (object)IntNTObj)
                        _value = null;
                    else
                        _value = IntNTObj._value;
                }
    
                /// <summary>
                /// Restituisce il valore intero
                /// </summary>
                public int Value
                {
                    get
                    {
                        if (this._value == null) throw new System.NullReferenceException();
                        return Convert.ToInt32(_value);
                    }
                    /*set 
                    { 
                        _value = value;
                    } */
                }
    
                /// <summary>
                /// converte dal tipo-base intero al tipo IntNT
                /// </summary>
                /// <param name="i"></param>
                /// <returns></returns>
                public static implicit operator IntNT(int i)
                {
                    return new IntNT((object)i);
                }
    
                /// <summary>
                /// converte dal IntNT intero al tipo tipo-base
                /// </summary>
                /// <param name="o"></param>
                /// <returns></returns>
                public static implicit operator int(IntNT o)
                {
                    return o.Value;
                }
    
                /// <summary>
                /// converte il dbnull nel tipo IntNT
                /// </summary>
                /// <param name="dbn"></param>
                /// <returns></returns>
                public static implicit operator IntNT(System.DBNull dbn)
                {
                    return new IntNT();
                }
    
                public static implicit operator IntNT(string str)
                {
                    if (IsInt(str)) return new IntNT(Convert.ToInt32(str));
                    else return new IntNT();
                }
    
                // è intero solo se è numerico e senza virgola.
                public static bool IsInt(string str)
                {
                    if (str == null) return false;
                    return (str.IndexOf(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator) < 0); // && DecimalNT.IsNumeric(str)
                }
    
                #region IFormattable Members
    
                public string ToString(string format, IFormatProvider formatProvider)
                {
                    if (format != null)
                    {
                        if (format.IndexOf('|') > 0)
                        {
                            string[] split = format.Split('|');
                            for (int i = 0; i < split.Length; i++)
                            {
                                if (split[i].IndexOf('=') >= 0)
                                {
                                    string[] split2 = split[i].Split('=');
                                    if (base.ToString() == split2[0]) return split2[1];
                                }
                            }
                        }
                        return ((System.IFormattable)_value).ToString(format, formatProvider);
                    }
                    return base.ToString();
                }
    
                #endregion
    
            }
        }
    
    }


    As explained previously, we have built these types before the nullable came out, to easily handle the mapping between empty fields in web forms, and fields in the database.
    So there's a NT type for int, decimal, string, boolean and so on.

    After that we deployed custom classes and collections, whose properties are bound to the fields of a table using a DAL library.
    You can look at it like a sort of very earlier Entity Framework, since we don't write these classes manually, of course; we wrote a code generator for that.
    It connects to the db, let's you choose table and it generates custom classes, custom collections and CRUD and Find stored procedures.

    so basicly a custom generated class lookes like this

    PersonCollectionProvider prov = new PersonCollectionProvider() //used to populate the instance of a collection or class and manage db connection
    Person employee = new Person();
    PersonCollection  employees = new PersonCollection();
    class members are the NTTypes mapped to the table fields:

    employee.IdXst23 (IntNT)
    employee.Name (StringNT)

    Classes and collections have methods to save, update and delete to the database.
    So when I have a new record to insert, like in this case, I fill the object properties except for the Id, since it is mapped to an Identity column in the database, and call the method:

    employee.Save();
    
    //or, if I have more objects to save
    employees.Add(employee);
    emloyees.SaveCollection();
    After saving the Id member is automatically populated from the db.
    So of course the IdXst23 as Id property is null when I bind to the Store an object for a new record; it is never null for a DB retrieved instance or collection since the ID member is mapped to an identity Key Column.

    I hope that the picture is more clear to you now, of course an id property can't be null, but when I insert a new record I don't have it since it should comes from the DB after insert.
    Last edited by lapix; Feb 17, 2012 at 11:39 AM.
  10. #10

    Sample Code

    I include some simple test code you can use to reproduce the problem.

    You can use the NullType definition of the previous message, then use this class as test object:

    Person Class
    using System;
    using System.Text;
    using xTLayer;
    
    namespace TestClass
    {
        public class Person
        {
            public Person(xTLayer.Nulltypes.IntNT idXst23, string name)
            {
                this.IdXst23 = idXst23;
                this.Name = name;
            }
    
            public Person()
            {
            }
    
            public xTLayer.Nulltypes.IntNT IdXst23 { get; set; }
            public string Name { get; set; }
        }
    }
    Sample page with a formpanel and store

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Test._Default" %>
    <%@ Register assembly="Ext.Net" namespace="Ext.Net" tagprefix="ext" %>
    
    <!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></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <ext:ResourceManager ID="ResourceManager1" runat="server" />
                <ext:Store runat="server" ID="StoreTest" UseIdConfirmation="true">
                <Reader>
                    <ext:JsonReader IDProperty="IdXst23">
                        <Fields>
    <%--                        <ext:RecordField Name="IdXst23">
                            <Convert Handler="return parseString(value);" />
                            </ext:RecordField>--%>
                            <ext:RecordField Name="Name"/>
                        </Fields>
                    </ext:JsonReader>
                </Reader>
                <UpdateProxy>
                    <ext:HttpWriteProxy Method="POST" Url="Save.ashx" />
                </UpdateProxy>
            </ext:Store>
            <ext:FormPanel runat="server" ID="testForm" LabelAlign="Top" Width="200" Height="300" Layout="FormLayout">
            <Items>
                <ext:TextField runat="server" ID="txtName" DataIndex="Name" AnchorHorizontal="50"/>
            </Items>
            <Buttons>
            <ext:Button ID="btnSave" runat="server" Text="Save">
            <DirectEvents>
                <Click OnEvent="btnSave_Click" />
            </DirectEvents>
            <Listeners>
            <Click Handler="#{StoreTest}.addRecord(#{testForm}.getForm().getFieldValues(false, 'dataIndex'),false, true);#{StoreTest}.save();" />
            </Listeners>
            </ext:Button>
            </Buttons>
            </ext:FormPanel>    
        </form>
    </body>
    </html>
    Page codebehind:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using TestClass;
    using Ext.Net;
    
    
    namespace Test
    {
        public partial class _Default : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                
            }
    
            protected void btnSave_Click(object sender, DirectEventArgs e)
            {
            }
        }
    }
    Handler:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Services;
    using xTLayer;
    using TestClass;
    using Ext.Net;
    
    namespace Test
    {
        /// <summary>
        /// Summary description for $codebehindclassname$
        /// </summary>
        [WebService(Namespace = "http://tempuri.org/")]
        [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
        public class Save : IHttpHandler
        {
    
            public void ProcessRequest(HttpContext context)
            {
    
                Person employee = new Person();
                Response sr = new Response(true);
                var handler = new StoreDataHandler(context);
    
                ChangeRecords<Person> data = handler.ObjectData<Person>();
                ConfirmationList confirmlist = handler.BuildConfirmationList("IdXst23");
    
                foreach (Person emp in data.Created)
                {
                    employee = emp;
                    employee.IdXst23 = 21; //emulating save to DB and retrieve Identity Key
                    confirmlist[emp.IdXst23].ConfirmRecord(employee.IdXst23);
                }
    
    
                StoreResponseData response = new StoreResponseData();
                response.Confirmation = confirmlist;
    
                sr.Data = response.ToString();
                sr.Write();
            }
    
            public bool IsReusable
            {
                get
                {
                    return false;
                }
            }
        }
    }
    as you debug the handler, you can see the JSON exception.
Page 1 of 2 12 LastLast

Similar Threads

  1. [CLOSED] Access Grid Data Store and manually store to database
    By macap in forum 1.x Legacy Premium Help
    Replies: 8
    Last Post: Oct 05, 2011, 8:52 AM
  2. How to save DataView to the database?
    By wkcode in forum 1.x Help
    Replies: 1
    Last Post: Jan 19, 2011, 8:24 AM
  3. Replies: 3
    Last Post: Apr 20, 2010, 5:24 PM
  4. Save in database
    By flaviodamaia in forum 1.x Help
    Replies: 4
    Last Post: Nov 06, 2008, 7:16 AM
  5. Data back on a Store.save()
    By Dave.Sanders in forum 1.x Legacy Premium Help
    Replies: 2
    Last Post: Sep 03, 2008, 1:03 PM

Posting Permissions