Re: [RavenDB] "Undo" property changes

57 views
Skip to first unread message

Oren Eini (Ayende Rahien)

unread,
Aug 22, 2016, 11:24:53 AM8/22/16
to ravendb

Hibernating Rhinos Ltd  

Oren Eini l CEO Mobile: + 972-52-548-6969

Office: +972-4-622-7811 l Fax: +972-153-4-622-7811

 


On Mon, Aug 22, 2016 at 4:46 PM, Morten Kristensen <ma...@morten.eu> wrote:
I tried posting this question an hour or so ago, but can't seem to find it anywhere, so i hope this is not a duplicate.

I'm looking for a way to retrieve the unmodified value of a property within a single session.

Say i have the following document:

{
   
"Id": "MyDocuments/1",
   
"Property": [
       
"OtherDocuments/2", "OtherDocuments/3"
   
]
}

I then update it (without saving):

var myDocument = session.Load<MyDocument>(1);
myDocument
.Property = new List<string> {
   
"OtherDocuments/4"
}

In another part of the code (still within the same session though) i would like to:

var unmodifiedProperty = session.Load<MyDocument>(myDocument.Id).Property; // Hoped this would load the unmodified (yet cached) version of the document - but it's the same instance as the one i modified.

Is there any way to do this without having to clone the original instance and carry it through the entire workflow?

I know the WhatChanged() method can show me the specific changes, but it would require a lot of unnecessary code to recreate the unmodified value from the DocumentChanges objects.

--
You received this message because you are subscribed to the Google Groups "RavenDB - 2nd generation document database" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Kijana Woodard

unread,
Aug 22, 2016, 11:46:02 AM8/22/16
to rav...@googlegroups.com
What's your goal? Audit log?

Morten Kristensen

unread,
Aug 22, 2016, 11:50:16 AM8/22/16
to RavenDB - 2nd generation document database
If i understand the Refresh method correctly, it is used to determine if (and apply) any changes has occured outside of the current session?
What i really want is to fetch the values present at the first "Load".

I noticed there's a private "entityAndMetadata" collection property on the session instance, containing the exact values (in JObject form though) i'm looking for.
It also seems to be the value passed to the "BeforeStore" method in IDocumentStoreListeners. 

Is there any way to access that value?
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+u...@googlegroups.com.

Morten Kristensen

unread,
Aug 22, 2016, 11:53:17 AM8/22/16
to RavenDB - 2nd generation document database
The context is actually authorization. 
I need to know both the original values AND the new values (in combination) to determine if the document can be saved. 
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+u...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "RavenDB - 2nd generation document database" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+u...@googlegroups.com.

Kijana Woodard

unread,
Aug 22, 2016, 11:57:09 AM8/22/16
to rav...@googlegroups.com
Since you brought it up, what would be good/bad about using the Before Store listener here?


To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+unsubscribe@googlegroups.com.

Morten Kristensen

unread,
Aug 22, 2016, 12:06:34 PM8/22/16
to RavenDB - 2nd generation document database
The execution context (i need access to the session and user context while performing the validation).
Based on whether the first document can be saved, more documents may have to be queried and/or saved.
Correct me if I'm wrong, but store listeners are mostly used for data validation, not business validation? 

Kijana Woodard

unread,
Aug 22, 2016, 12:27:20 PM8/22/16
to rav...@googlegroups.com
Given what you say, even if it was possible to get to the session, etc [might be, not sure], it would get fairly messy tp have that much logic tucked away in a listener IMO.

It sounds like the problem is that it's two separate bits of code acting independently yet trying to tunnel information through the session. If you looked at the value, then made the updates, and looked a the new value in the same bit of code, seems straight forward.

Is this "wide open" or are there a limited set of things that matter?
What I'm thinking is loading up the document in a delegating handler or middleware and storing the relevant "before" values in the request context somewhere. 

You may need a Clone. You should be able to use json.net to clone [serialize, deserialize] since the document obviously serializes fine already. It's strange, but I'm guessing the perf won't matter.

Another thought, do you need both bits of data to do the auth check or can it be "bool BeforeValuesMeetAuthCriteria"?

To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+unsubscribe@googlegroups.com.

Morten Kristensen

unread,
Aug 22, 2016, 1:13:51 PM8/22/16
to RavenDB - 2nd generation document database
Hi Kijana, first of all, thanks for taking the time to help - much appreciated.

I agree on the listeners being too cluttered.
Cloning the loaded object is absolutely an option, but is also an option i was actively trying to avoid.

I would much prefer calling 
_authorizationHandler.EnsureCanSave(modifiedDocument);

over having to administrate and pass the cloned unmodified document along.

By delegating handler or middleware you mean some kind of internal dictionary containing a copy of the loaded document (not much unlike the session)?
This could be an option, but how would this be automatically populated without a lot of extra boilerplate?

Another thought, do you need both bits of data to do the auth check or can it be "bool BeforeValuesMeetAuthCriteria"?

If you're thinking:

var document = session.Load<MyDocument>(1);

//Do BeforeValuesMeetAuthCriteria here
document
.Property = ...
// Do AfterValuesMeetAuthCriteria here

It's what I'm trying to avoid I'm afraid :o(

Kijana Woodard

unread,
Aug 22, 2016, 1:22:30 PM8/22/16
to rav...@googlegroups.com
> By delegating handler or middleware you mean some kind of internal dictionary containing a copy of the loaded document (not much unlike the session)?

I'm making assumptions about your environment [web api or aspnet core]. Sticking things in Request.Current.Items or similar. It would be quite like session, except you wouldn't have to worry about raven getting confused [imagine storing some other document in session that held the "before state"].

I was further boiling it down to, in the request pipeline, determine that "everything is ok auth-wise" and just putting a bool in the request context. Then in your _authorizationHandler, checking that the bool is true and the modified state is ok.

I'm blind as to the complexity of these auth checks.


To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+unsubscribe@googlegroups.com.

Oren Eini (Ayende Rahien)

unread,
Aug 22, 2016, 2:09:01 PM8/22/16
to ravendb
This refresh the object to its current server side state, regardless of whatever changes happened.
The internal value is not exposed.
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+unsubscribe@googlegroups.com.

Kijana Woodard

unread,
Aug 22, 2016, 4:48:09 PM8/22/16
to rav...@googlegroups.com
He still needs the changed values to save, assuming the auth checks pass.

Oren Eini (Ayende Rahien)

unread,
Aug 23, 2016, 3:59:14 AM8/23/16
to ravendb
Then he need to copy it to the side on load

Morten Kristensen

unread,
Aug 23, 2016, 4:47:42 AM8/23/16
to RavenDB - 2nd generation document database
This is what I'm trying to avoid. Cloning an object just to pass it along the entire stack creates a certain code smell if you ask me, 
especially since I'm already tied closely to the DocumentSession, and i know that it's able to recreate exactly what I'm looking for.

I've implemented a method to recreate the values of a property (Lists and structs) based on the WhatChanged method available.
This is also far from optimal, but better than the alternative IMO, and seems to work as i had hoped.

I will share the result once it's properly implemented.
Reply all
Reply to author
Forward
0 new messages