While working on the database-independent tests, I ran across
ReflectonObjectFactory.Parse(), and wondered if there was a way to
improve this method. It currently contains:
var assemblyTypes = assembly.GetTypes();
foreach (Type type in assemblyTypes)
{
if (type.IsAbstract)
continue;
foreach (Type i in type.GetInterfaces())
{
if (i.Assembly.GetCustomAttributes(typeof(DbLinqAttribute),
false).Length > 0)
{
IList<Type> types;
if (!interfaceImplementations.TryGetValue(i, out types))
interfaceImplementations[i] = types = new List<Type>();
types.Add(type);
}
}
}
This is less than ideal for two reasons:
1. It uses Assembly.GetTypes(), which thus "pulls in" private types
which we probably don't care about.
2. It increases memory requirements, as we're loading more Type
instances than we actually need.
3. It increases disk usage (as more Reflection information needs to be
read from-disk to populate the Type instances).
4. It's slower than it could be, due to (1), (2) and (3).
(1) is "easily" fixed by using Assembly.GetExportedTypes(), which only
returns public types, but the biggest performance and memory issues are
due to (2) and (3).
A better solution (in terms of memory and execution time) is to use an
assembly-level attribute:
// within DbLinq.dll:
[AttributeUsage(AttributeTargets.Assembly)]
public class DbLinqProviderAttribute {
public DbLinqProviderAttribute(Type providerType);
public Type ProviderType {get;}
}
// within e.g. DbLinq.Sqlite.dll
[assembly:DbLinqProvider(typeof(SqliteVendor))]
This turns the O(n*m) (n=types, m=interfaces for each type) algorithm
used in ReflectonObjectFactory.Parse() into an O(1) algorithm, improving
execution time and lowering memory requirements (as we don't need to
allocate a potentially large array from Assembly.GetTypes(), etc.).
The downside is that it slightly complicates the provider assembly, as
they need to use the DbLinqProvider attribute, but I think this may be
worthwhile.
However, my biggest problem with the algorithm isn't within Parse() but
instead within ParseAppDomain():
4. It processes most assemblies within the current AppDomain (and only
those assemblies).
This limitation turned up when I was creating the
DbLinq.SqlServer_test_ndb project: it required that I have a strong
reference to the DbLinq.SqlServer assembly from my test assembly.
The problem, specifically, is the use of the NullConnection type, e.g.
from MsSqlDataContextTest.cs:
return new DataContext(new NullConnection(), new
AttributeMappingSource());
In this case, we're not providing a connection string (deliberately, as
we don't actually want to connect to a database), and thus there is no
explicit reference to the provider that we want to test. This is
undesirable; it's only acceptable for now because the default provider
is the SqlServer provider, which is what I was testing, but this should
not remain the situation for long.
Thus, a question: when using the
DataContext(IDbConnection,MappingSource) constructor, how should we
specify which provider assembly should actually be used? The current
code within DataContext.cs doesn't support using an IDbConnection with a
non-SqlServer provider:
private void Init(IDatabaseContext databaseContext, MappingSource
mappingSource, IVendor vendor)
{
if (databaseContext == null)
throw new ArgumentNullException("databaseContext");
_VendorProvider = ObjectFactory.Get<IVendorProvider>();
if (vendor == null)
Vendor =
_VendorProvider.FindVendorByProviderType(typeof(SqlClient.Sql2005Provider));
else
Vendor = vendor;
Non-SqlServer providers aren't supported because vendor will be null,
thus prompting Init() to try to find the SqlClient.Sql2005Provider
provider. Oops.
Possible solutions would be to check to see if the IDbConnection
instance implements the IVendor interface, and use that if appropriate
(though this doesn't seem quite right, given the
IVendor.CreateDbConnection() method), or have the IDbConnection type
implement IVendorProvider (and ignore the providerType parameter in the
IVendorProvider.FindVendorByProviderType() method).
I'm not really sure what the ideal solution here is, and would welcome
any additional input.
Thanks,
- Jon
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"DbLinq" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/dblinq?hl=en
-~----------~----~----~----~------~----~------~--~---