Skip to content

Commit 21d49b2

Browse files
committed
Support in domain types + instantiation in Storage driver
1 parent 29feacb commit 21d49b2

File tree

4 files changed

+125
-6
lines changed

4 files changed

+125
-6
lines changed

Orm/Xtensive.Orm/Orm/Configuration/DomainTypeRegistry.cs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ public class DomainTypeRegistry : TypeRegistry
2626
private readonly static Type iModuleType = typeof (IModule);
2727
private readonly static Type iUpgradeHandlerType = typeof (IUpgradeHandler);
2828
private readonly static Type keyGeneratorType = typeof (KeyGenerator);
29-
private static readonly Type ifulltextCatalogNameBuilder = typeof (IFullTextCatalogNameBuilder);
29+
private readonly static Type ifulltextCatalogNameBuilder = typeof(IFullTextCatalogNameBuilder);
30+
private readonly static Type iConnectionHandlerType = typeof(IConnectionHandler);
31+
32+
private Type[] connectionHandlers;
3033

3134
/// <summary>
3235
/// Gets all the registered persistent types.
@@ -100,6 +103,27 @@ public IEnumerable<Type> FullTextCatalogResolvers
100103
get { return this.Where(IsFullTextCatalogNameBuilder); }
101104
}
102105

106+
/// <summary>
107+
/// Gets all the registered <see cref="IConnectionHandler"/> implementations.
108+
/// </summary>
109+
public IEnumerable<Type> ConnectionHandlers
110+
{
111+
get {
112+
// a lot of access to this property. better to have items cached;
113+
if (IsLocked) {
114+
if (connectionHandlers == null) {
115+
var container = new List<Type>(10);// not so many handlers expected
116+
foreach (var type in this.Where(IsConnectionHandler))
117+
container.Add(type);
118+
connectionHandlers = container.Count == 0 ? Array.Empty<Type>() : container.ToArray();
119+
}
120+
return connectionHandlers;
121+
}
122+
// if instacne is not locked then there is a chance of new handlers appeared
123+
return this.Where(IsConnectionHandler);
124+
}
125+
}
126+
103127
#region IsXxx method group
104128

105129
/// <summary>
@@ -238,6 +262,21 @@ public static bool IsFullTextCatalogNameBuilder(Type type)
238262
return false;
239263
}
240264

265+
/// <summary>
266+
/// Determines whether the <paramref name="type"/> is
267+
/// a connection handler.
268+
/// </summary>
269+
/// <param name="type">The type to check.</param>
270+
/// <returns>Check result.</returns>
271+
public static bool IsConnectionHandler(Type type)
272+
{
273+
if (type.IsAbstract) {
274+
return false;
275+
}
276+
277+
return iConnectionHandlerType.IsAssignableFrom(type) && iConnectionHandlerType != type;
278+
}
279+
241280
#endregion
242281

243282
#region ICloneable members

Orm/Xtensive.Orm/Orm/Providers/StorageDriver.cs

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2003-2010 Xtensive LLC.
1+
// Copyright (C) 2009-2021 Xtensive LLC.
22
// All rights reserved.
33
// For conditions of distribution and use, see license.
44
// Created by: Denis Krjuchkov
@@ -7,7 +7,10 @@
77
using System;
88
using System.Collections.Generic;
99
using System.Linq;
10+
using System.Linq.Expressions;
11+
using System.Reflection;
1012
using Xtensive.Core;
13+
using Xtensive.Linq;
1114
using Xtensive.Orm.Logging;
1215
using Xtensive.Orm.Configuration;
1316
using Xtensive.Orm.Model;
@@ -24,13 +27,18 @@ namespace Xtensive.Orm.Providers
2427
/// </summary>
2528
public sealed partial class StorageDriver
2629
{
30+
private static readonly MethodInfo FactoryCreatorMethod = typeof(StorageDriver)
31+
.GetMethod(nameof(CreateNewHandler), BindingFlags.Static | BindingFlags.NonPublic);
32+
2733
private readonly DomainConfiguration configuration;
2834
private readonly SqlDriver underlyingDriver;
2935
private readonly SqlTranslator translator;
3036
private readonly TypeMappingRegistry allMappings;
3137
private readonly bool isLoggingEnabled;
3238
private readonly bool hasSavepoints;
3339

40+
private readonly IReadOnlyDictionary<Type, Func<IConnectionHandler>> handlerFactoriesCache;
41+
3442
public ProviderInfo ProviderInfo { get; private set; }
3543

3644
public StorageExceptionBuilder ExceptionBuilder { get; private set; }
@@ -86,7 +94,7 @@ public DbDataReaderAccessor GetDataReaderAccessor(TupleDescriptor descriptor)
8694
public StorageDriver CreateNew(Domain domain)
8795
{
8896
ArgumentValidator.EnsureArgumentNotNull(domain, "domain");
89-
return new StorageDriver(underlyingDriver, ProviderInfo, domain.Configuration, GetModelProvider(domain));
97+
return new StorageDriver(underlyingDriver, ProviderInfo, domain.Configuration, GetModelProvider(domain), handlerFactoriesCache);
9098
}
9199

92100
private static DomainModel GetNullModel()
@@ -140,13 +148,69 @@ private void FixExtractionResultSqlServerFamily(SqlExtractionResult result)
140148
}
141149
}
142150

151+
private IReadOnlyCollection<IConnectionHandler> CreateConnectionHandlersFast(IEnumerable<Type> connectionHandlerTypes)
152+
{
153+
if (handlerFactoriesCache == null)
154+
return Array.Empty<IConnectionHandler>();
155+
var instances = new List<IConnectionHandler>(handlerFactoriesCache.Count);
156+
foreach (var type in connectionHandlerTypes) {
157+
if (handlerFactoriesCache.TryGetValue(type, out var factory)) {
158+
instances.Add(factory());
159+
}
160+
}
161+
return instances.ToArray();
162+
}
163+
164+
private static IReadOnlyCollection<IConnectionHandler> CreateConnectionHandlers(IEnumerable<Type> connectionHandlerTypes,
165+
out IReadOnlyDictionary<Type, Func<IConnectionHandler>> factories)
166+
{
167+
factories = null;
168+
169+
List<IConnectionHandler> instances;
170+
Dictionary<Type, Func<IConnectionHandler>> factoriesLocal;
171+
172+
if (connectionHandlerTypes is IReadOnlyCollection<Type> asCollection) {
173+
if (asCollection.Count == 0)
174+
return Array.Empty<IConnectionHandler>();
175+
instances = new List<IConnectionHandler>(asCollection.Count);
176+
factoriesLocal = new Dictionary<Type, Func<IConnectionHandler>>(asCollection.Count);
177+
}
178+
else {
179+
if (connectionHandlerTypes.Any())
180+
return Array.Empty<IConnectionHandler>();
181+
instances = new List<IConnectionHandler>();
182+
factoriesLocal = new Dictionary<Type, Func<IConnectionHandler>>();
183+
}
184+
185+
foreach (var type in connectionHandlerTypes) {
186+
var ctor = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null);
187+
if (ctor == null) {
188+
throw new NotSupportedException(string.Format(Strings.ExConnectionHandlerXHasNoParameterlessConstructor, type));
189+
}
190+
191+
var handlerFactory = (Func<IConnectionHandler>) FactoryCreatorMethod.MakeGenericMethod(type).Invoke(null, null);
192+
instances.Add(handlerFactory());
193+
factoriesLocal[type] = handlerFactory;
194+
}
195+
factories = factoriesLocal;
196+
return instances.ToArray();
197+
}
198+
199+
private static Func<IConnectionHandler> CreateNewHandler<T>() where T : IConnectionHandler
200+
{
201+
return FastExpression.Lambda<Func<IConnectionHandler>>(
202+
Expression.Convert(Expression.New(typeof(T)), typeof(IConnectionHandler)))
203+
.Compile();
204+
}
205+
143206
// Constructors
144207

145208
public static StorageDriver Create(SqlDriverFactory driverFactory, DomainConfiguration configuration)
146209
{
147210
ArgumentValidator.EnsureArgumentNotNull(driverFactory, "driverFactory");
148211
ArgumentValidator.EnsureArgumentNotNull(configuration, "configuration");
149212

213+
var handlers = CreateConnectionHandlers(configuration.Types.ConnectionHandlers, out var factories);
150214
var driverConfiguration = new SqlDriverConfiguration {
151215
ForcedServerVersion = configuration.ForcedServerVersion,
152216
ConnectionInitializationSql = configuration.ConnectionInitializationSql,
@@ -156,11 +220,14 @@ public static StorageDriver Create(SqlDriverFactory driverFactory, DomainConfigu
156220
var driver = driverFactory.GetDriver(configuration.ConnectionInfo, driverConfiguration);
157221
var providerInfo = ProviderInfoBuilder.Build(configuration.ConnectionInfo.Provider, driver);
158222

159-
return new StorageDriver(driver, providerInfo, configuration, GetNullModel);
223+
return new StorageDriver(driver, providerInfo, configuration, GetNullModel, factories);
160224
}
161225

162-
private StorageDriver(
163-
SqlDriver driver, ProviderInfo providerInfo, DomainConfiguration configuration, Func<DomainModel> modelProvider)
226+
private StorageDriver(SqlDriver driver,
227+
ProviderInfo providerInfo,
228+
DomainConfiguration configuration,
229+
Func<DomainModel> modelProvider,
230+
IReadOnlyDictionary<Type, Func<IConnectionHandler>> factoryCache)
164231
{
165232
underlyingDriver = driver;
166233
ProviderInfo = providerInfo;
@@ -171,6 +238,7 @@ private StorageDriver(
171238
hasSavepoints = underlyingDriver.ServerInfo.ServerFeatures.Supports(ServerFeatures.Savepoints);
172239
isLoggingEnabled = SqlLog.IsLogged(LogLevel.Info); // Just to cache this value
173240
ServerInfo = underlyingDriver.ServerInfo;
241+
handlerFactoriesCache = factoryCache;
174242
}
175243
}
176244
}

Orm/Xtensive.Orm/Strings.Designer.cs

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Orm/Xtensive.Orm/Strings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3467,4 +3467,7 @@ Error: {1}</value>
34673467
<data name="ExCantModifyActiveOrDisposedScope" xml:space="preserve">
34683468
<value>Can't modify Active or Disposed scope.</value>
34693469
</data>
3470+
<data name="ExConnectionHandlerXHasNoParameterlessConstructor" xml:space="preserve">
3471+
<value>Connection handler '{0}' has no parameterless constructor.</value>
3472+
</data>
34703473
</root>

0 commit comments

Comments
 (0)