New Posts New Posts RSS Feed: SaveOption EntityTypesExcludedFromPostSaveRefetch does no work as expected
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

SaveOption EntityTypesExcludedFromPostSaveRefetch does no work as expected

 Post Reply Post Reply
Author
HerbertL View Drop Down
Newbie
Newbie


Joined: 16-Mar-2011
Posts: 3
Post Options Post Options   Quote HerbertL Quote  Post ReplyReply Direct Link To This Post Topic: SaveOption EntityTypesExcludedFromPostSaveRefetch does no work as expected
    Posted: 16-Mar-2011 at 2:46am

I have a table with a primary key of type char(7) (CharPK), a timestamp field (ts) and a date field (LastUpdated) which is automatically updated to getdate() by a table trigger. The timestamp field is defined with concurrency strategy "Client" in the EF model.
I define AfterGet interceptors for all string-fields (including the primary key field) in the table to trim the trailing spaces of char-fields and to guarantee that optional string fields do not return Nothing:

 <AfterGet(EntityPropertyNames.(CharPK), AfterGet(EntityPropertyNames.OtherCharFields)>
  Public Function TrimMultipleProps(ByVal strPropValue As String) As String
    If Not String.IsNullOrEmpty(strPropValue) Then
      If strPropValue.EndsWith(" ") Then
        Return strPropValue.TrimEnd()
      Else
        Return strPropValue
      End If
    Else
      'Guarantee to not return Nothing
      Return String.Empty
    End If
  End Function

When I do this I cannot save new entities with PKs shorter than seven characters because the PK is trimmed and when DevForce reads the record after saving it detects a difference and throws an exception.
Therefore I suppress reading after save:

Dim so As New SaveOptions()
so.EntityTypesExcludedFromPostSaveRefetch = New List(Of Type) From {GetType(EntityWithCharPK)}
_mgr.DefaultSaveOptions = so

In this situation mgr.SaveChanges submits SQL like this:

exec sp_executesql N'update [dbo].[TableWithCharPK]
set [SomeColumn] = @0
where (([CharPK] = @1) and ([ts] = @2))
select [LastUpdated], [Created], [ts], [ComputedColumn1], [ComputedColumn2]
from [dbo].[TableWithCharPK]
where @@ROWCOUNT > 0 and [CharPK] = @1',N'@0 varchar(25),@1 char(7),@2 binary(8)',@0='f',@1='1234   ',@2=0x000000000011D6EA

At first I was impressed because exactly the necessary columns are read after the update.
The problem is, that none of the values in the select list are actually read into the entity.
The timestamp value in the entity stays unchanged after a save operation.
When I try to save this entity a second time, DevForce throws an error because it detects a concurrency problem because of the outdated timestamp value.

Is this a bug or am I'm missing something?

Thanks

Herbert

Back to Top
kimj View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 09-May-2007
Posts: 1391
Post Options Post Options   Quote kimj Quote  Post ReplyReply Direct Link To This Post Posted: 18-Mar-2011 at 5:15pm
The ExcludeFromPostSaveRefresh means that the entity won't be updated with any database-generated changes from triggers or timestamp fields, or identity columns too.  You don't want to use this option when an entity will be modified from what it contained at the point of the save to what it looks like when actually committed to the DB table.  By default, DevForce will automatically "refresh" saved entities so that they accurately reflect what is in the database; you should only use ExcludeFromPostSaveRefresh for entity types which don't require a refresh. 
Back to Top
HerbertL View Drop Down
Newbie
Newbie


Joined: 16-Mar-2011
Posts: 3
Post Options Post Options   Quote HerbertL Quote  Post ReplyReply Direct Link To This Post Posted: 21-Mar-2011 at 1:31am

Thanks for the reply. But it still leaves the question why something is read in after the update when it is not used. That's a waste of resources.

My original problem was how I can achive that a Property of a char primary key is automatically trimmed. Example: The customer ID stored in the database is 'ABCD   ' (char(7). The value of the Property Customer.ID should provide 'ABCD'. Do you know a solution for this?

Thanks Herbert

Back to Top
kimj View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 09-May-2007
Posts: 1391
Post Options Post Options   Quote kimj Quote  Post ReplyReply Direct Link To This Post Posted: 21-Mar-2011 at 10:44am
DevForce does a Refresh on the underlying EF ObjectContext after the save.  It's EF, via the Refresh, which determines the query to issue.  The query will include any property marked as "store-generated", along with concurrency columns.
 
Property interceptors should help with your original problem.  Take a look at the documentation here - http://drc.ideablade.com/xwiki/bin/view/Documentation/Property-Interceptors
Back to Top
HerbertL View Drop Down
Newbie
Newbie


Joined: 16-Mar-2011
Posts: 3
Post Options Post Options   Quote HerbertL Quote  Post ReplyReply Direct Link To This Post Posted: 22-Mar-2011 at 12:55am

Please, read my thread. Property interceptors were my first try. But they didn't work with a primary key of type char.

>>DevForce does a Refresh on the underlying EF ObjectContext after the save.  It's EF, via the Refresh, which determines the query to issue.  The query will include any property marked as "store-generated", along with concurrency columns.

If DevForce does a refresh, why doesn't it really refresh the object, after it has queried the new values?

Thanks Herbert

Back to Top
kimj View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 09-May-2007
Posts: 1391
Post Options Post Options   Quote kimj Quote  Post ReplyReply Direct Link To This Post Posted: 22-Mar-2011 at 10:58am
The EF Refresh and ExcludeFromPostSaveRefresh are working correctly.  EF refreshes the appropriate columns and pushes them back into the entity, unless the entity is excluded.
 
Back to your problem with the char(7) primary key.  If you try to insert a new item with the trimmed key it's EF that will complain during the Refresh about the wrong number of rows being retrieved.
 
You can resolve the issue by using a BeforeSet property interceptor on the CharPK property to pad it.  Along with the BeforeGet which trims the values you should have the behavior you want: trimmed data in your UI yet padded data stored in the DB and refreshed correctly.  Because the entity contains timestamp and trigger-updated columns you cannot exclude it from refresh.  The interceptor would look something like this (the overload you use doesn't matter):
 
<BeforeSet(EntityPropertyNames.CharPK)> _
Public Sub BeforeSetId(args As PropertyInterceptorArgs(Of TableWithCharPK, [String]))
 args.Value = args.Value.PadRight(7)
End Sub 
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down