I'm using 2.6 runtime.
Your understanding is correct, except for step 4. In telerik grid, I cannot cancel the update. Instead I get an ItemUpdated event that contains the exception. So I handle it like this, where HandleInsertUpdateException is my function that deals with printing the error message.
private static void grid_ItemUpdated(object source, GridUpdatedEventArgs e)
{
if (e.Exception != null)
{
HandleInsertUpdateException((source as RadGrid), e, false);
e.ExceptionHandled = true;
e.KeepInEditMode = true;
}
}
My LLBLGENProDataSource2 control is initialized as follows:
public static void Initialize(LLBLGenProDataSource2 ds, Type entityFactoryType)
{
ds.AdapterTypeName = typeof(DataAccessAdapter).AssemblyQualifiedName;
ds.DataContainerType = DataSourceDataContainerType.EntityCollection;
ds.EntityFactoryTypeName = entityFactoryType.AssemblyQualifiedName;
ds.CacheLocation = DataSourceCacheLocation.Session;
ds.DataBinding += new EventHandler(ds_DataBinding);
ds.EntityUpdated += new EventHandler<DataSourceActionEventArgs>(ds_EntityUpdated);
ds.EntityUpdating += new EventHandler<CancelableDataSourceActionEventArgs>(ds_EntityUpdating);
ds.EnablePaging = false;
//LivePersistence causes LLBLGenProDataSource2 to auto-generate insert/update/delete statements,
//which saves a lot of manual effort.
ds.LivePersistence = true;
}
In my DataAccessAdapter, I override SaveEntity as follows:
public override bool SaveEntity(IEntity2 entityToSave, bool refetchAfterSave, IPredicateExpression updateRestriction, bool recurse)
{
try
{
return base.SaveEntity(entityToSave, refetchAfterSave, updateRestriction, recurse);
}
catch (ORMQueryExecutionException ORMex)
{
int errorNumber = (int)ORMex.DbSpecificExceptionInfo[ExceptionInfoElement.ErrorNumber];
//Check for primary key violations and unique constraint violations
if (errorNumber == 2627 || errorNumber == 2601)
throw new ORMEntityValidationException("Duplicate record found.", entityToSave);
else
throw ORMex; //rethrow
}
//Other exceptions should bubble up
}
And my validator looks like this:
[Serializable]
[DependencyInjectionInfo(typeof(TradeRestrictionEntity), "Validator", ContextType = DependencyInjectionContextType.NewInstancePerTarget)]
public class TradeRestrictionValidator : ValidatorBase
{
public override void ValidateEntityBeforeSave(IEntityCore involvedEntity)
{
TradeRestrictionEntity e = (TradeRestrictionEntity)involvedEntity;
// Validate date ranges
if (e.ExpiryDate.HasValue && (e.StartDate > e.ExpiryDate))
throw new ORMEntityValidationException("Start date cannot be greater than expiry date.", e);
// Validate overlapping times
using (DataAccessAdapter adapter = new DataAccessAdapter())
{
LinqMetaData md = new LinqMetaData(adapter);
IQueryable<TradeRestrictionEntity> q = from t in md.TradeRestriction
where t.AcctCode == e.AcctCode
&&
(
(t.StartDate == e.StartDate) ||
(t.StartDate < e.StartDate && (t.ExpiryDate == null || t.ExpiryDate >= e.StartDate)) ||
(t.StartDate > e.StartDate && (e.ExpiryDate == null || t.StartDate <= e.ExpiryDate))
)
select t;
if (!e.IsNew) {
q = q.Where(x => x.TradeRestrictionId != e.TradeRestrictionId);
}
if (q.Count() > 0)
throw new ORMEntityValidationException("Another trade restriction overlaps with supplied date range for the same account.", e);
}
}
}
When the user presses cancel, even if I call Databind on LLBLGenDataSource2 or on the grid, the user updated data is still displayed in the grid. The only way to get original data to display back is to do a full refresh of the page by navigating to the page directly even within the same ASP.NET session.
I cannot seem to understand whether it's the LLBLGenDataSource2 control that incorrectly caches the data or whether it's the grid keeping the data in its viewstate or I'm just doing something very wrong. Thank you.