Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ISession.Refresh does not update lazy properties #3622

Open
ValResnick opened this issue Nov 7, 2024 · 3 comments
Open

ISession.Refresh does not update lazy properties #3622

ValResnick opened this issue Nov 7, 2024 · 3 comments

Comments

@ValResnick
Copy link

Hi,

we have noticed a problem in versions 4.4.9 and 5.5.2. In version 5.2.1 we did not have this problem, I suspect it is related to the lazy property changes in version 5.3 (116398d).

The following scenario:
We have opened a session with objects and also open another session and edit an object there, which is already loaded in the first session. We call Refresh so that this object is up-to-date in the previous session. Unfortunately, in the versions above, the lazy properties are no longer updated, but contain the previous and therefore old value.

Reproduction:

[Test] // In Class FetchLazyPropertiesFixture
public void Bug()
{
	using (var outerSession = OpenSession())
	{
		const string query = "from Person fetch Image where Id = 1";
		const string namePostFix = "_MODIFIED";
		const int imageLength = 4711;
		
		Person outerPerson = outerSession.CreateQuery(query).UniqueResult<Person>();
		
		Assert.That(outerPerson.Name.EndsWith(namePostFix), Is.False); // Normal property 
		Assert.That(outerPerson.Image.Length, Is.EqualTo(1)); // Lazy Property
		
		// Changing the properties of the person in a different sessions
		using (var innerSession = OpenSession())
		{
			var transaction = innerSession.BeginTransaction();
		
			Person innerPerson = innerSession.CreateQuery(query).UniqueResult<Person>();
			innerPerson.Image = new byte[imageLength];
			innerPerson.Name += namePostFix;
			innerSession.Update(innerPerson);
			
			transaction.Commit();
		}
		
		// Refreshing the person in the outer session
		outerSession.Refresh(outerPerson);
		
		Assert.That(outerPerson.Name.EndsWith(namePostFix), Is.True); // Value has changed
		Assert.That(outerPerson.Image.Length, Is.EqualTo(imageLength)); // This is still the old value
	}                                                                                                 
}

Best regards,
Thomas

@ValResnick
Copy link
Author

ValResnick commented Nov 7, 2024

Hello again,

I found out that if I always inject a new interceptor in the method PocoEntityTuplizer.AfterInitialize, my test runs through.
This will certainly not be the solution, but I hope it can help?

public override void AfterInitialize(object entity, ISessionImplementor session)  
{                                                                                 
	if (IsInstrumented)                                                           
	{                                                                             
		// var interceptor = _enhancementMetadata.ExtractInterceptor(entity);     
		// if (interceptor == null)                                               
		// {                                                                      
		// 	interceptor = _enhancementMetadata.InjectInterceptor(entity, session);
		// }                                                                      
		// else                                                                   
		// {                                                                      
		// 	interceptor.Session = session;                                        
		// }                                                                      
                                                                                  
		var interceptor = _enhancementMetadata.InjectInterceptor(entity, session);
		interceptor?.ClearDirty();                                                
	}                                                                             
}                                                                                 

Best regards,
Thomas

@ValResnick
Copy link
Author

ValResnick commented Nov 8, 2024

Hi,

i have created a draft patch file, which should fix the problem. The problem is, that i am using some obsolete methods...
But maybe this can help to find a better fix.

Bugfix_Issue_3622.patch
The patch is created for Version 4.4.9

Best regards,
Thomas

@mpool
Copy link

mpool commented Nov 28, 2024

After looking at the patch, instead of creating a new issue, I think it is appropriate for me to add on here that I don't believe this is isolated to lazy properties or stateful sessions. I think the Refresh method is just broke for both ISession and IStatelessSession.

This simple test case fails on the last line as the entity value is still 1:

var myEntity1 = statelessSession1.Get<MyEntity>(101);
var myEntity2 = statelessSession2.Get<MyEntity>(101);

myEntity1.Value = 1;
statelessSession1.Update(myEntity1);

statelessSession2.Refresh(myEntity2);
Assert.Equal(1, myEntity2.Value);

myEntity1.Value = 2;
statelessSession1.Update(myEntity1);

statelessSession2.Refresh(myEntity2);
Assert.Equal(2, myEntity2.Value);

I've debugged it down through almost the exact same code path as the above patch. It appears Loader.cs is issuing the query to the db, but then it get snagged in the GetRow method as its key being already loaded, thus bypassing binding/hydration.

Great job on adding a patch @ValResnick !

EDIT: NH 5.5.2 / Fluent NH 3.4.0

EDIT 2: My mistake, the async version of Refresh appears to be having the same behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants