Jeff
Jeff

Reputation: 36603

Entity Framework 4.0 Doesn't Work With Computed Properties

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.

Upvotes: 4

Views: 968

Answers (2)

Jeff
Jeff

Reputation: 36603

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.

Upvotes: 1

Akash Kava
Akash Kava

Reputation: 39956

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

Upvotes: 1

Related Questions