- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
When updating an entity always a new entity.
Joined: 12-Jun-2012
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
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.
Joined: 12-Jun-2012
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.
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)