Hi,

If I have an Entity (e.g. MyEntity) with 3 fields (SomeInt, SomeString, SomeOtherEntity) where SomeOtherEntity is of type MyOtherEntity, is there a way that I can mark that changes to the field MyEntity.SomeOtherEntity should NOT change the version of MyEntity, but changes to SomeInt and SomeString should change the version?

Also, if the above is possible, then is the following possible:

Two users (in two different sessions) get an instance of the same MyEntity entity at the same time. One user changes the SomeInt field, the other changes the SomeOtherEntity field. Will a version conflict exception be thrown?

Thanks!

This thread was imported from our support forum. The original discussion may contain more detailed answer.

asked Mar 11 '10 at 23:51

ara's gravatar image

ara
395858791

you marked your MyEntity class with [Version]? If yes, then remove this atrribute from class and put [Version] just on fields you want to be included in Version.

(Mar 11 '10 at 23:51) Peter Ĺ ulek Peter%20%C5%A0ulek's gravatar image

One Answer:

Likely, you know there are two kinds of versions:

  • Automatic. All non-lazy fields are included there.

  • Manual. Field(s) marked by [Version] form such a version.

And, after studying this code, it's clear that when multiple fields are marked by [Version], you won't get expected result. Instead, all of them will be incremented.

So currently there is no way to achieve this, and this is an architectural mistake. We'll fix it ASAP - likely, [Version(Increment = true)] will be available to explicitly mark fields that must be updated (as you see, currently we either update all marked ones, or include all non-lazy fields into it).

The workaround you have now is to declare a special field, mark it by [Version], and override HandleUpdateVersionInfo in such a way that it really updates this field only when changedField passed to it is one of expected ones.


No: reference properties are actually lazily resolved, but loaded as usual. I.e. Key of referenced entity is available, so technically, we consider we know the value of this property. But its conversion to externally visible value may require fetch.

So changing Address.Country value will lead to version change.

Btw, it's quite easy to check this: see the value of address.VersionInfo in debugger. Its representation there is Tuple.ToString() (there is [DebuggerDisplay("{Value}")], and Value is Tuple), and it includes address.Country.Key value.


it isn't possible to mark a property to be excluded from VersionInfo, but it's possible to mark the properties that must be included there.

I'll think about adding this feature as well - although I'm not fully sure if this is a good idea:

  • We expect version difference really indicates there are changes. E.g. we use this info when merging two DisconnectedStates.

  • So if you'd occasionally violate this rule, there is a chance you won't get the difference merged and thus it won't be shown in UI.

  • Lazy load fields are excluded from VersionInfo just because it's very logical. We expect if such field is changed, something else must be changed as well to indicate version is changed. Or you must use a single [Version] field, which is automatically updated by DO4.

Also note:

  • [Version] attribute currently works as expected, if it is applied to just one field. This field is auto-incremented (or auto-updated for Guids & DateTime fields), when entity is changing for the first time in the current transaction.

  • If it is applied to multiple fields, you must block this code by overriding Entity.HandleVersionInfoUpdate. Otherwise all of such fields will be updated (bug).

  • EntitySet property updates are tracked only when [Version] is used. Otherwise there is simply "no room" to reflect the changes there. You can disable this by overriding Entity.HandleVersionInfoUpdate.

And finally, generally we assume just one of two options is used to track versions:

  • Default behavior: all fields except lazy compose the version. Consequences: slower VersionInfo building, larger amount of version data, but no additional space in DB. A => B => A change won't be detected (A == A); Can't track changes in EntitySets.

  • Custom version field: few fields (btw, currently they MUST BE declared in [HierarchyRoot] - to ensure they're always available - will explain this later), ideally - a single one. Auto or manually updated, VersionInfo building is fast, small amount of version data, but additional space in DB. A => B => A change is detected by default; can track changes in EntitySets.

Concerning placement of [Version] field in [HierarchyRoot] (or in its ancestors): this is necessary to ensure that getting VersionInfo won't lead to any additional queries. In default case this can lead to an additional query, since nearly all entity fields compose VersionInfo, and if the entity was loaded as result of query to one of its ancestor types (i.e. it's a Dog, but it was materialized by Query.All<animal>() query), such a query will occur if you'll try to get VersionInfo.

That's why we decided to block an ability to declare custom [Version] fields in types other than [HierarchyRoot] and its ancestors: ideally, VersionInfo must be always accessible w/o any queries.

This also explains why we don't allow to mark some fields as "excluded from VersionInfo": from the point of view described here, this is simply unreasonable.

But now I think we must not limit you too much here by our own logic (customers are always right ;) ). So shortly we'll provide the following new implementation:

  • [Version([Excluded = true|false], [Updatable = true|false])]

And you'll be able to come to the ideas described above by your own ;) Joking, of course, but think about them - two above cases generally cover everything:

  • Default case is cool, because it works by default. There are some trade-offs, but as I said, it works by default ;)

  • Case with an additional field covers everything else: it is fast, requires no coding by default (just add [Version]!), allows you to implement custom update logic, track only necessary fields, etc. Btw, [Version(Excluded = true)] would be helpful here - e.g. disabling change tracking in many of EntitySets seems a good idea.

answered Mar 12 '10 at 19:05

Alex%20Yakunin's gravatar image

Alex Yakunin
29714412

In mdissel's example, would it be possible to somehow mark that changes of the Country property's value should NOT change the version?

(Mar 12 '10 at 19:05) ara ara's gravatar image

So if i understand versioning correctly:

if you have an entity Address with a property Country of type Country (by default lazy loaded), changing the country does not increment the version?

Thanks Marco

(Mar 12 '10 at 19:05) Marco Marco's gravatar image

> Will a version conflict exception be thrown?

Yes. If versions aren't equal, it's conflict.

(Mar 12 '10 at 19:05) Alex Yakunin Alex%20Yakunin's gravatar image
Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!
toggle preview

Subscription:

Once you sign in you will be able to subscribe for any updates here

Tags:

×573

Asked: Mar 11 '10 at 23:51

Seen: 2,457 times

Last updated: Mar 11 '10 at 23:51

powered by OSQA