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

Do not store mapping field in Configuration #3398

Merged
merged 16 commits into from
Aug 15, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 1 addition & 10 deletions src/NHibernate.Test/DialectTest/MsSql2008DialectFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,16 +148,7 @@ public void ScaleTypes()
Assert.That(dialect.GetTypeName(SqlTypeFactory.GetTime(max + 1)), Is.EqualTo("time").IgnoreCase, "Over max time");
}

private static readonly FieldInfo _mappingField =
typeof(Configuration).GetField("mapping", BindingFlags.Instance | BindingFlags.NonPublic);

private static IMapping GetMapping(Configuration cfg)
{
Assert.That(_mappingField, Is.Not.Null, "Unable to find field mapping");
var mapping = _mappingField.GetValue(cfg) as IMapping;
Assert.That(mapping, Is.Not.Null, "Unable to find mapping object");
return mapping;
}
private static IMapping GetMapping(Configuration cfg) => (IMapping) cfg.BuildSessionFactory();
Copy link
Member Author

Choose a reason for hiding this comment

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

The true equivalent for the original code in the new way would be GetMapping(Configuration cfg) => cfg.BuildMapping(), but Dialect would throw an InvalidOperationException. However, in this case it does not matter and we can use fully resolved session factory instead.

Copy link
Member

Choose a reason for hiding this comment

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

Now new public "BuildMapping" can be used.

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 was thinking about it and don't like it. cfg.BuildMapping just should not exist as it provides an incomplete version of mapping, that can create a lot of problems.

Copy link
Member

@bahusoid bahusoid Aug 15, 2023

Choose a reason for hiding this comment

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

nit: I don't understand your concern. In my understanding IMapping was specifically designed to be safely used in "uncompiled" state. See interface description:

/// Defines operations common to "compiled" mappings (ie. <c>SessionFactory</c>) and
/// "uncompiled" mappings (ie <c>Configuration</c> that are used by implementors of <c>IType</c>

So as long you use interface methods and don't do some funny castings you should be safe.

You agreed to keep method public - so it would be good to have it in tests too.

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 don't think the IMapping was designed. It was probably appeared incidentally from some other bad design decision. Problem with the interface that it is not clear when it is safe to use compiled or raw mappings. For example, SingleTableEntityPersister accepts both IMapping and ISessionFactoryImplementor. Can it use only ISessionFactoryImplementor?

public SingleTableEntityPersister(PersistentClass persistentClass, ICacheConcurrencyStrategy cache,
ISessionFactoryImplementor factory, IMapping mapping)
: base(persistentClass, cache, factory)

This is really not clear.

Also, Hibernate has removed this interface and redesigned the mapping compilation.


private static void AssertSqlType(IType type, SqlType sqlType, IMapping mapping)
{
Expand Down
79 changes: 31 additions & 48 deletions src/NHibernate/Cfg/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ public Configuration(SerializationInfo info, StreamingContext context)
FilterDefinitions = GetSerialedObject<IDictionary<string, FilterDefinition>>(info, "filterDefinitions");
Imports = GetSerialedObject<IDictionary<string, string>>(info, "imports");
interceptor = GetSerialedObject<IInterceptor>(info, "interceptor");
mapping = GetSerialedObject<IMapping>(info, "mapping");
NamedQueries = GetSerialedObject<IDictionary<string, NamedQueryDefinition>>(info, "namedQueries");
NamedSQLQueries = GetSerialedObject<IDictionary<string, NamedSQLQueryDefinition>>(info, "namedSqlQueries");
namingStrategy = GetSerialedObject<INamingStrategy>(info, "namingStrategy");
Expand All @@ -124,7 +123,7 @@ public void GetObjectData(SerializationInfo info, StreamingContext context)
{
ConfigureProxyFactoryFactory();
SecondPassCompile();
Validate();
Validate(BuildMapping());
bahusoid marked this conversation as resolved.
Show resolved Hide resolved

info.AddValue("entityNotFoundDelegate", EntityNotFoundDelegate);

Expand All @@ -139,7 +138,6 @@ public void GetObjectData(SerializationInfo info, StreamingContext context)
info.AddValue("filterDefinitions", FilterDefinitions);
info.AddValue("imports", Imports);
info.AddValue("interceptor", interceptor);
info.AddValue("mapping", mapping);
info.AddValue("namedQueries", NamedQueries);
info.AddValue("namedSqlQueries", NamedSQLQueries);
info.AddValue("namingStrategy", namingStrategy);
Expand Down Expand Up @@ -238,18 +236,18 @@ public bool HasNonIdentifierPropertyNamedId(string className)
}

public Dialect.Dialect Dialect =>
NHibernate.Dialect.Dialect.GetDialect(configuration.Properties);
throw new InvalidOperationException("The dialect is not ready at this stage of the configuration.");
hazzik marked this conversation as resolved.
Show resolved Hide resolved
}

[Serializable]
private class StaticDialectMappingWrapper : IMapping
{
private readonly IMapping _mapping;

public StaticDialectMappingWrapper(IMapping mapping)
public StaticDialectMappingWrapper(IMapping mapping, Dialect.Dialect dialect)
{
_mapping = mapping;
Dialect = mapping.Dialect;
Dialect = dialect;
}

public IType GetIdentifierType(string className)
Expand All @@ -275,20 +273,12 @@ public bool HasNonIdentifierPropertyNamedId(string className)
public Dialect.Dialect Dialect { get; }
}

private IMapping mapping;

protected Configuration(SettingsFactory settingsFactory)
{
InitBlock();
this.settingsFactory = settingsFactory;
Reset();
}

private void InitBlock()
{
mapping = BuildMapping();
}

public virtual IMapping BuildMapping()
{
return new Mapping(this);
Expand Down Expand Up @@ -548,9 +538,8 @@ private void AddValidatedDocument(NamedXmlDocument doc)
public void AddDeserializedMapping(HbmMapping mappingDocument, string documentFileName)
{
if (mappingDocument == null)
{
throw new ArgumentNullException("mappingDocument");
}
throw new ArgumentNullException(nameof(mappingDocument));

try
{
var dialect = new Lazy<Dialect.Dialect>(() => Dialect.Dialect.GetDialect(properties));
Expand Down Expand Up @@ -745,9 +734,8 @@ public Configuration AddResource(string path, Assembly assembly)
public Configuration AddResources(IEnumerable<string> paths, Assembly assembly)
{
if (paths == null)
{
throw new ArgumentNullException("paths");
}
throw new ArgumentNullException(nameof(paths));

foreach (var path in paths)
{
AddResource(path, assembly);
Expand Down Expand Up @@ -934,6 +922,9 @@ public static bool IncludeAction(SchemaAction actionsSource, SchemaAction includ
/// <param name="dialect"></param>
public string[] GenerateSchemaCreationScript(Dialect.Dialect dialect)
{
var m = BuildMapping();
var mapping = new StaticDialectMappingWrapper(m, dialect);

SecondPassCompile();

var defaultCatalog = GetQuotedDefaultCatalog(dialect);
Expand Down Expand Up @@ -1001,11 +992,11 @@ public string[] GenerateSchemaCreationScript(Dialect.Dialect dialect)
return script.ToArray();
}

private void Validate()
private void Validate(IMapping mapping)
{
ValidateEntities();
ValidateEntities(mapping);

ValidateCollections();
ValidateCollections(mapping);

ValidateFilterDefs();
}
Expand Down Expand Up @@ -1059,15 +1050,15 @@ private void ValidateFilterDefs()
}
}

private void ValidateCollections()
private void ValidateCollections(IMapping mapping)
{
foreach (var col in collections.Values)
{
col.Validate(mapping);
}
}

private void ValidateEntities()
private void ValidateEntities(IMapping mapping)
{
bool validateProxy = PropertiesHelper.GetBoolean(Environment.UseProxyValidator, properties, true);
HashSet<string> allProxyErrors = null;
Expand Down Expand Up @@ -1281,8 +1272,7 @@ protected virtual void ConfigureProxyFactoryFactory()
//http://nhibernate.jira.com/browse/NH-975

var ipff = Environment.BytecodeProvider as IInjectableProxyFactoryFactory;
string pffClassName;
properties.TryGetValue(Environment.ProxyFactoryFactoryClass, out pffClassName);
properties.TryGetValue(Environment.ProxyFactoryFactoryClass, out var pffClassName);
if (ipff != null && !string.IsNullOrEmpty(pffClassName))
{
ipff.SetProxyFactoryFactory(pffClassName);
Expand All @@ -1299,33 +1289,22 @@ protected virtual void ConfigureProxyFactoryFactory()
/// <returns>An <see cref="ISessionFactory" /> instance.</returns>
public ISessionFactory BuildSessionFactory()
{
var dynamicDialectMapping = mapping;
// Use a mapping which does store the dialect instead of instantiating a new one
// at each access. The dialect does not change while building a session factory.
// It furthermore allows some hack on NHibernate.Spatial side to go on working,
// See nhibernate/NHibernate.Spatial#104
mapping = new StaticDialectMappingWrapper(mapping);
try
{
ConfigureProxyFactoryFactory();
SecondPassCompile();
Validate();
Environment.VerifyProperties(properties);
Settings settings = BuildSettings();
var m = BuildMapping();
var settings = BuildSettings();
var mapping = new StaticDialectMappingWrapper(m, settings.Dialect);
hazzik marked this conversation as resolved.
Show resolved Hide resolved
ConfigureProxyFactoryFactory();
SecondPassCompile();
Validate(mapping);
Environment.VerifyProperties(properties);

// Ok, don't need schemas anymore, so free them
Schemas = null;
// Ok, don't need schemas anymore, so free them
Schemas = null;

return new SessionFactoryImpl(
this,
mapping,
settings,
GetInitializedEventListeners());
}
finally
{
mapping = dynamicDialectMapping;
}
return new SessionFactoryImpl(this, mapping, settings, GetInitializedEventListeners());
}

/// <summary>
Expand Down Expand Up @@ -2358,6 +2337,8 @@ private static T[] AppendListeners<T>(T[] existing, T[] listenersToAdd)
/// <seealso cref="NHibernate.Tool.hbm2ddl.SchemaUpdate"/>
public string[] GenerateSchemaUpdateScript(Dialect.Dialect dialect, IDatabaseMetadata databaseMetadata)
{
var m = BuildMapping();
var mapping = new StaticDialectMappingWrapper(m, dialect);
SecondPassCompile();

var defaultCatalog = GetQuotedDefaultCatalog(dialect);
Expand Down Expand Up @@ -2438,6 +2419,8 @@ public string[] GenerateSchemaUpdateScript(Dialect.Dialect dialect, IDatabaseMet

public void ValidateSchema(Dialect.Dialect dialect, IDatabaseMetadata databaseMetadata)
{
var m = BuildMapping();
var mapping = new StaticDialectMappingWrapper(m, dialect);
SecondPassCompile();

var defaultCatalog = GetQuotedDefaultCatalog(dialect);
Expand Down
Loading