4

I have an updatable view that is mapped in entity framework (edmx designer)

Everything works well and good until I add a property to my updatable view (and entity) that is marked with a StoreGeneratedPattern of Computed. Once I do that, upon saving my modified entity:

var user = objectContext.Users.FirstOrDefault(u => u.Id == 123);

// user is detached and some operations are performed...
// then it's re-attached to a new ObjectContext and has its ObjectStateEntry set to Modified

secondObjectContextInstance.SaveChanges() // throws exception: 


 The property 'Id' is part of the object's key information and cannot be modified.


at System.Data.Objects.EntityEntry.VerifyEntityValueIsEditable(StateManagerTypeMetadata typeMetadata, Int32 ordinal, String memberName)
   at System.Data.Objects.EntityEntry.GetAndValidateChangeMemberInfo(String entityMemberName, Object complexObject, String complexObjectMemberName, StateManagerTypeMetadata& typeMetadata, String& changingMemberName, Object& changingObject)
   at System.Data.Objects.EntityEntry.EntityMemberChanging(String entityMemberName, Object complexObject, String complexObjectMemberName)
   at System.Data.Objects.EntityEntry.EntityMemberChanging(String entityMemberName)
   at System.Data.Objects.ObjectStateEntry.System.Data.Objects.DataClasses.IEntityChangeTracker.EntityMemberChanging(String entityMemberName)
   at System.Data.Objects.Internal.SnapshotChangeTrackingStrategy.SetCurrentValue(EntityEntry entry, StateManagerMemberMetadata member, Int32 ordinal, Object target, Object value)
   at System.Data.Objects.Internal.EntityWrapper`1.SetCurrentValue(EntityEntry entry, StateManagerMemberMetadata member, Int32 ordinal, Object target, Object value)
   at System.Data.Objects.EntityEntry.SetCurrentEntityValue(StateManagerTypeMetadata metadata, Int32 ordinal, Object userObject, Object newValue)
   at System.Data.Objects.ObjectStateEntryDbUpdatableDataRecord.SetRecordValue(Int32 ordinal, Object value)
   at System.Data.Mapping.Update.Internal.UpdateTranslator.SetServerGenValue(PropagatorResult context, Object value)
   at System.Data.Mapping.Update.Internal.UpdateTranslator.BackPropagateServerGen(List`1 generatedValues)
   at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
   at System.Data.EntityClient.EntityAdapter.Update(IEntityStateManager entityCache)
   at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
   at System.Data.Objects.ObjectContext.SaveChanges()

I have not changed the value of Id. In fact, I can reproduce this error if I don't change ANYTHING at all and simply re-attach to the second ObjectContext, set Modified, and call Save.

I can see the SQL generated for the update reflects that I have set this property as computed:

exec sp_executesql N'update [dbo].[UsersView]
set [UserName] = @0, [LastName] = @1, [FirstName] = @2, [MiddleName] = @3, [Suffix] = null, [Pid] = @4, [IsLoggedIn] = @5, [DisplayName] = @10
where ([Id] = @12)
select [ComputedProperty]
from [dbo].[UsersView]
where @@ROWCOUNT > 0 and [Id] = @12',N'@0 nvarchar(35),@1 nvarchar(35),@2 nvarchar(35),@3 nvarchar(35),@4 nvarchar(4),@5 bit,@6 bit,@7 bit,@8 nvarchar(max) ,@9 nvarchar(max) ,@10 nvarchar(max) ,@11 int,@12 int',@0=N'yaya',......

Again, everything works perfectly, without any problem until I set ComputedProperty to have a StoreGeneratedPattern of Computed. It seems like this must have something to do with the additional SELECT statement added to the update SQL in the above...because the exception happens AFTER the updates SQL is already executed.

What's wrong here?

Thanks.

Jeff
  • 35,755
  • 15
  • 108
  • 220
  • What do you mean by updatable view and how did you map it. This works without problems when you use tables. – Ladislav Mrnka Jan 02 '12 at 08:44
  • I mean I have a SQL Server view with Instead Of Insert, Update, and Delete triggers defined. I'm using the approach here to solve the scope_identity issue: http://stackoverflow.com/questions/5820992/error-when-inserting-into-table-having-instead-of-trigger-from-entity-data-frame – Jeff Jan 02 '12 at 18:36
  • I wonder if my instead of update trigger has the same "select id..." in last line and if that's screwing it up somehow...will post back shortly... – Jeff Jan 02 '12 at 18:37

2 Answers2

1

Setting object state entry's state to modified will cause every property to be set as modified. Instead you should only mark properties that are modified explicitly as shown in this answer. Entity framework 4, update specific properties

Community
  • 1
  • 1
Akash Kava
  • 39,066
  • 20
  • 121
  • 167
  • 1
    Setting state to modified will affect only properties with `StoreGeneratedPattern` set to `None`. Properties with `StoreGeneratedPattern` set to `Identity` or `Computed` should not be affected. – Ladislav Mrnka Jan 02 '12 at 08:42
1

Well, I guess you could call it my own stupidity, but the behavior is kind of non intuitive.

In case anyone else implements INSTEAD OF triggers to enable updatable views via EF, it should be noted that the implementation described here: error when inserting into table having instead of trigger from entity data framework should ONLY be used for the INSTEAD OF INSERT trigger, NOT the INSTEAD OF UPDATE trigger. Adding a SELECT to the end of the instead of update trigger will result in the exception described in the question.

Community
  • 1
  • 1
Jeff
  • 35,755
  • 15
  • 108
  • 220