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

Clean-up IObjectsFactory usages #1781

Conversation

fredericDelaporte
Copy link
Member

@fredericDelaporte fredericDelaporte commented Jul 3, 2018

IObjectsFactory is meant for instantiating NHibernate dependencies, but it was used in some cases for instantiating value types. Some of its methods are also hard or impossible to implement with many dependency injection frameworks.

Follow up to #1758

Possible breaking change:

  • Users providing some custom logic for instantiating value types will now need to supply their own result transformer if they were using AliasToBeanResultTransformer with value types, or their own entity tuplizer if they were using value types as entities.
  • Users providing some custom logic for instantiating their custom session contexts will have to implement ICurrentSessionContextWithFactory and add a parameterless public constructor to their custom context, and move their custom instantiation logic from IObjectsFactory.CreateInstance(Type, object[]) to IObjectsFactory.CreateInstance(Type).

ScriptSplitter splitter = (ScriptSplitter)objFactory.CreateInstance(typeof(ScriptSplitter), sql);

foreach (string stmt in splitter)
foreach (var stmt in new ScriptSplitter(sql))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed on #1758, the ScriptSplitter does not expose anything overridable, and so it cannot benefit from being instantiated by the object factory: it cannot supply a custom implementation.

@@ -85,7 +85,7 @@ public override object TransformTuple(object[] tuple, String[] aliases)
{
result = _resultClass.IsClass
? _beanConstructor.Invoke(null)
: Cfg.Environment.ObjectsFactory.CreateInstance(_resultClass, true);
: Activator.CreateInstance(_resultClass, true);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed in #1758, this usage is not a dependency but a DTO instantiation. If the user wants some custom behavior for instantiating value types, he now would have to provide its own transformer.

@@ -103,7 +103,7 @@ private object GetInstance()
}
if (mappedClass.IsValueType)
{
return Cfg.Environment.ObjectsFactory.CreateInstance(mappedClass, true);
return Activator.CreateInstance(mappedClass, true);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed in #1758, this usage is not a dependency but an entity instantiation. If the user wants some custom behavior for instantiating value types, he now would have to provide its own tuplizer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that the true here is required.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably in some partial trust or similar environments.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have just preferred to be quite conservative, inlining the default previous implementation "as is".

@@ -1261,35 +1261,65 @@ private void Init()

private ICurrentSessionContext BuildCurrentSessionContext()
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not change this method and would not change the standard contexts' constructors. Also I would make the ICurrentSessionContextWithFactory interface optional.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this method is not changed then ICurrentSessionContextWithFactory would not have any usage and should not be kept.

So, do you mean you would not change just the direct instantiation cases?

About making ICurrentSessionContextWithFactory optional, then the obsoleted line:

(ICurrentSessionContext) Environment.ObjectsFactory.CreateInstance(implClass, this);

Would have to be replaced by:

(ICurrentSessionContext) Activator.CreateInstance(implClass, this);

In order to avoid leaving a non-obsoleted feature depending on an obsoleted one.

@fredericDelaporte

This comment has been minimized.

@hazzik
Copy link
Member

hazzik commented Jul 10, 2018

Shall we go further (in other PR) and replace IObjectsFactory with IServiceProvider?

@fredericDelaporte
Copy link
Member Author

Shall we go further (in other PR) and replace IObjectsFactory with IServiceProvider?

Yes, we should.


var context = (ISessionFactoryAwareCurrentSessionContext) Environment.ObjectsFactory.CreateInstance(implClass);
context.SetFactory(this);
return context;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking a lot about this chunk of code, but could not come up with a great solution, unfortunately.

So, I came up with this:

var implClass = ReflectHelper.ClassForName(impl);
var constructor = implClass.GetConstructor(new [] { typeof(ISessionFactoryImplementor) });
ICurrentSessionContext context;
if (constructor != null)
{
  context = (ICurrentSessionContext) constructor.Invoke(new object[] { this });
}
else
{
  context = (ICurrentSessionContext) Environment.ObjectsFactory.CreateInstance(implClass);
}
if (context is ISessionFactoryAwareCurrentSessionContext sessionFactoryAwareContext)
{
  sessionFactoryAwareContext.SetFactory(this);
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, changed for this. (And rebased.)

fredericDelaporte and others added 4 commits July 20, 2018 11:23
IObjectsFactory is meant for instantiating NHibernate dependencies, but
it was used in some cases for instantiating value types. Some of its
methods are also hard or impossible to implement with many dependency
injection frameworks.

Follow up to nhibernate#1758
Do an alternate cleanup for session context
Rename the added interface
Use session context creation logic from @hazzik

Co-authored-by: Alexander Zaytsev <hazzik@gmail.com>
@fredericDelaporte fredericDelaporte merged commit eec2ee6 into nhibernate:master Jul 21, 2018
@fredericDelaporte fredericDelaporte deleted the CleanUpObjectsFactoryUsages branch July 21, 2018 10:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants