When updating an entity always a new entity.

Posts   
 
    
mvdwert
User
Posts: 2
Joined: 12-Jun-2012
# Posted on: 12-Jun-2012 13:55:11   

Hi,

I am using LLBLGEN 2.6 in C# ASP.NET. I have a datagrid (devexpress xtragridview) that I have databound to an object datasource.

I have a database table with multiple columns as a primary key, when I edit an entity in the grid and edit the primary key then the entity is not updated but a new one is inserted.

It seems that the old values are not remembered to perform an update instead of an insert.

Here is an example of the code:

<dx:ASPxGridView ID="uniqueSellingPointASPxGridView" 
    ClientInstanceName="uniqueSellingPointASPxGridView" runat="server" AutoGenerateColumns="False" 
    DataSourceID="uniqueSellingPointObjectDataSource" KeyFieldName="CompositeKey" 
    Width="1256px" 
    OnCustomButtonCallback="uniqueSellingPointASPxGridView_CustomButtonCallback" 
    OnInitNewRow="uniqueSellingPointASPxGridView_InitNewRow" 
    OnRowValidating="uniqueSellingPointASPxGridView_RowValidating">
    <Columns>
        <dx:GridViewCommandColumn VisibleIndex="0" ShowInCustomizationForm="True" ButtonType="Link">
            <EditButton Visible="True">
            </EditButton>
            <NewButton Visible="True">
            </NewButton>
            <ClearFilterButton Visible="True">
            </ClearFilterButton>
            <CustomButtons>
                <dx:GridViewCommandColumnCustomButton ID="deleteButton" Text="Delete">
                </dx:GridViewCommandColumnCustomButton>
            </CustomButtons>
        </dx:GridViewCommandColumn>
        <dx:GridViewDataTextColumn FieldName="ProductNumber"  Caption="Product number"
            ShowInCustomizationForm="True" VisibleIndex="0" ReadOnly="True">
            <PropertiesTextEdit>
                <ReadOnlyStyle BackColor="#CCCCCC">
                </ReadOnlyStyle>
            </PropertiesTextEdit>
        </dx:GridViewDataTextColumn>
        <dx:GridViewDataComboBoxColumn FieldName="CatalogCode" VisibleIndex="1" 
            Caption="Catalog">
            <PropertiesComboBox DataSourceID="catalogObjectDataSource" TextField="Name" 
                ValueField="Code" ValueType="System.String">
            </PropertiesComboBox>
        </dx:GridViewDataComboBoxColumn>
        <dx:GridViewDataComboBoxColumn FieldName="LanguageCode" VisibleIndex="2" 
            Caption="Language">
            <PropertiesComboBox DataSourceID="languageObjectDataSource" TextField="Name" 
                ValueField="Code" ValueType="System.String">
            </PropertiesComboBox>
        </dx:GridViewDataComboBoxColumn>
        <dx:GridViewDataTextColumn FieldName="UniqueSellingPoint" 
            ShowInCustomizationForm="True" VisibleIndex="3">
        </dx:GridViewDataTextColumn>
        <dx:GridViewDataCheckColumn FieldName="Active" ShowInCustomizationForm="True" 
            VisibleIndex="4">
        </dx:GridViewDataCheckColumn>
    </Columns>
    <ClientSideEvents CustomButtonClick="function(s, e) {
        if(e.buttonID == 'deleteButton') {
            if (confirm ('Are you sure you want to delete this item?')) {
                e.processOnServer = true;
            }
        }
        else {
            e.processOnServer = true;
        }
     }" />
    <SettingsBehavior AllowGroup="False"
        AllowSort="True" AllowDragDrop="False" ConfirmDelete="True" />
    <SettingsPager Position="TopAndBottom">
    </SettingsPager>
    <Settings ShowFilterRow="True" />
</dx:ASPxGridView>

<asp:ObjectDataSource ID="uniqueSellingPointObjectDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}" 
    OnSelecting="uniqueSellingPointObjectDataSource_Selecting" 
    SelectMethod="GetUniqueSellingPoints" 
    TypeName="Paradigit.PIM.BLL.UniqueSellingPoint" 
    DataObjectTypeName="Paradigit.PIM.DAL.EntityClasses.UniqueSellingPointEntity" 
    InsertMethod="SaveUniqueSellingPoint" UpdateMethod="SaveUniqueSellingPoint">
    <SelectParameters>
        <asp:Parameter Name="productNumber" Type="String" />
    </SelectParameters>
</asp:ObjectDataSource>

        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, false)]
        public EntityCollection<UniqueSellingPointEntity> GetUniqueSellingPoints(string productNumber)
        {
            EntityCollection<UniqueSellingPointEntity> productFeatureValues = new EntityCollection<UniqueSellingPointEntity>(new UniqueSellingPointEntityFactory());

            IRelationPredicateBucket filter = new RelationPredicateBucket();
            filter.PredicateExpression.Add(PredicateFactory.CompareValue(UniqueSellingPointFieldIndex.ProductNumber, ComparisonOperator.Equal, productNumber));

            using (IDataAccessAdapter adapter = this.GetDataAccessAdapter())
            {
                adapter.FetchEntityCollection(productFeatureValues, filter);
            }

            return productFeatureValues;
        }

        /// <summary>
        /// Saves the unique selling point.
        /// </summary>
        /// <param name="uniqueSellingPointEntity">The unique selling point entity.</param>
        /// <returns></returns>
        [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Insert | System.ComponentModel.DataObjectMethodType.Update, false)]
        public bool SaveUniqueSellingPoint(UniqueSellingPointEntity uniqueSellingPointEntity)
        {
            using (IDataAccessAdapter adapter = this.GetDataAccessAdapter())
            {
                return adapter.SaveEntity(uniqueSellingPointEntity);
            }
        }

        #region Custom Entity code
        
        // __LLBLGENPRO_USER_CODE_REGION_START CustomEntityCode

        public string CompositeKey
        {
            get { return this.ProductNumber + "|-|" + this.CatalogCode + "|-|" + this.LanguageCode + "|-|" + this.UniqueSellingPoint; }
            set { }
        }

        // __LLBLGENPRO_USER_CODE_REGION_END
        #endregion
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39833
Joined: 17-Aug-2003
# Posted on: 12-Jun-2012 21:03:32   

If you edit the PK, it's in theory a new entity, as the only thing that identifies a piece of data as 'this entity' is the PK value. So if you change the PK, the bound datasourcecontrol can't find the original entity back to update the values of (as the PK changed!) so it inserts a new one.

PK's are immutable, you shouldn't edit them. If you need to, pick a new PK, e.g. an identity field.

Frans Bouma | Lead developer LLBLGen Pro
mvdwert
User
Posts: 2
Joined: 12-Jun-2012
# Posted on: 13-Jun-2012 09:52:26   

I assumed the entities generated by LLBLGEN kept a "shadow copy" of all primary key fields, and when the entity is changed (Is Dirty) and one of the primary key's has changed then an update is performed correctly changing the old primary key to the new one with an update.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39833
Joined: 17-Aug-2003
# Posted on: 13-Jun-2012 10:19:36   

It does, but that's not used for finding the original entity back in this particular case. However, it might very well be the grid calls ExecuteInsert instead of ExecuteUpdate on the entity in question. Either way, the datasourcecontrol doesn't compare on 'old pk values', just the existing ones.

Like I said, don't alter PK values, if you need to, choose a different PK field. It will bite you sooner or later anyway, as the updated entity has to be updated in the DB, which forces Fk fields to be altered as well. While that might be happening through cascading rules in the FK constraint, it's not always possible (e.g. when there are multiple paths from A to B)

Frans Bouma | Lead developer LLBLGen Pro