The attached patch removes
DbLinq.Vendor.Implementation.Vendor.TypeToLoadData() and implements
support for the DbLinqConnectionType parameter, thus allowing my sample
program to work (which isn't in the patch).
Permission to commit?
Also, should the DbLinqProvider parameter be renamed to DbLinqVendor, as
that appears to be its actual purpose (specifying which DbLinq vendor to
use).
Which leaves only one last quibble: DbLinqConnectionType is verbose
(which is probably why the vendor assemblies were being tied to a
vendor, so that this wouldn't need to be mentioned everywhere).
An possible solution is to support an assembly-level
DbLinqConnectionTypeAttribute attribute, which would specify the
connection type to use if a DbLinqConnectionType isn't specified in the
connection string. Assembly.GetCallingAssembly() would be used to
lookup this attribute, so no AppDomain crawling would be implied.
We could similarly support an assembly-level DbLinqVendorAttribute
attribute, which would specify the vendor to use if
DbLinqProvider/DbLinqVendor isn't found in the connections string.
Thoughts?
- Jon
On Tue, 2009-03-10 at 08:13 +0100, Pascal Craponne wrote:
> Of course I agree.
>
>
>
> We used to name the layers as follows:
> 1. User code (or maybe application)
> 2. DbLinq core
> 3. DbLinq vendors, because there is an IVendor interface there
> 4. Database drivers, because that's how everyone names them :)
>
>
> So as I said, I agree. Vendors MUST NOT be tight to drivers in any
> way, just because of the old Oracle MS/ODP, and the new
> SQLite/Mono.SQLite drivers.
>
>
> For people who read this, Jon's ideas relate to a thread we started a
> few months ago, and that's probably a way to satisfy everyone (DbLinq
> and Mono), without leaving DbLinq custom DataContext ctors behind.
>
> Pascal.
>
> jabber/gtalk: [email protected]
> msn: [email protected]
>
>
>
>
> On Tue, Mar 10, 2009 at 04:52, Jonathan Pryor <[email protected]> wrote:
>
> This is an appeal for standardizing nomenclature and cleaning
> the architecture.
>
> At present, in order to do anything useful, 4 layers are
> involved:
>
> User Code, what the user writes, e.g. from user in
> db.Users....
> DbLinq, e.g. DataContext, what the user interacts
> with.
> Database Driver, e.g. DbLinq.Sqlite.dll, responsible
> for generating SQL which is sent to the provider.
> Database Provider, e.g. System.Data.SQLite.dll,
> responsible for interacting with the actual database.
>
> (RFC: Are these names appropriate? If not, what names should
> be used?)
>
> The benefit to this is code centralization: many databases
> have multiple different providers but accept the same SQL
> (e.g. Mono.Data.Sqlite vs. System.Data.SQLite,
> System.Data.OracleClient vs. Oracle.DataAccess, SqlClient vs.
> SqlCeClient, etc.). This is even more useful to prevent tying
> a driver to a particular provider version, allowing the
> provider to be easily updated to later versions without
> modifying the driver.
>
> Which brings us to the problem: parts of the current DbLinq
> vendor architecture tie the driver and provider layers
> together, specifically
> DbLinq.Vendor.Implementation.Vendor.TypeToLoadData(), used by
> Vendor.CreateDbConnection().
>
> (Then there is the the issue mentioned at [0], in which I
> consider parsing all types in all assemblies within the
> current AppDomain to be an abomination, which is related to
> this.)
>
> So, in code, the problem:
>
> string connectionString = "DbLinqProvider=Sqlite;Data
> Source=Northwind.db3";
> var dc = new DataContext(connectionString);
> var dcq = from p in dc.GetTable<Product>() where
> p.ProductName == "Pen" select p.ProductID;
> var cmd = dc.GetCommand(dcq);
> Console.WriteLine("# Command Type: {0}",
> cmd.GetType().FullName);
> // Prints "# Command Type: System.Data.SQLite.SQLiteCommand"
>
> This is a problem specifically for Mono, as (1) Mono will be
> bundling all the drivers into System.Data.Linq.dll, (2) I want
> Sqlite to be supported (simplifies testing, etc.), and (3)
> System.Data.SQLite.dll will not work under Mono (mixed mode
> assembly), so I need to use Mono.Data.Sqlite.dll. Since the
> current DbLinq.Sqlite.dll explicitly loads
> System.Data.SQLite.dll, this causes things to break rather
> badly when executing under Mono.
>
> The question: How do we fix this?
>
> First, what exactly is broken? Specifically, what is broken
> are the DataContext constructors which take a string
> connection string parameter, and use the connection string to
> deduce both the driver and the provider, so this impacts only
> the DataContext(string) constructor. If you use the
> DataContext(IDbConnection) constructor, then the original
> IDbConnection instance is used for creating subsequent
> IDbCommand instances, so all is well.
>
> Proposed Solution: I would suggest making the connection
> string parameters follow the naming scheme outlined above, and
> use a DbLinqDriver parameter to specify the DbLinq driver to
> use (Sqlite, Oracle, etc.). I would then use a
> DbLinqConnectionType parameter to be the Assembly Qualified
> Type that should be used to create the IDbConnection instance.
> This type must have a constructor taking a single string
> parameter. The current DbLinqProvider parameter would be
> removed (or kept as a synonym for DbLinqDriver, but I think
> down this path leads confusion.)
>
> This would allow the above code to work as expected while only
> changing the connection string to
>
> "DbLinqDriver=Sqlite;DbLinqConnectionType=Mono.Data.Sqlite.SqliteConnection,
> Mono.Data.Sqlite; Data Source=Northwind.db3". What I'm less sure about is
> whether assembly qualified type references including version information/etc.
> will be valid SQL connection strings; I'll need to look this up.
>
> Making this change would permit removing
> Vendor.GetProviderTypeName(), thus removing the implicit
> dependency the driver makes on the provider.
>
> Thoughts?
>
> - Jon
> [0]
>
> http://groups.google.com/group/dblinq/browse_thread/thread/76c943f6e02735e7/4e2ea660f68e006f?lnk=raot#4e2ea660f68e006f
>
>
>
>
>
>
>
>
>
>
> >
--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---
Index: src/DbLinq.SqlServer/SqlServerVendor.cs
===================================================================
--- src/DbLinq.SqlServer/SqlServerVendor.cs (revision 998)
+++ src/DbLinq.SqlServer/SqlServerVendor.cs (working copy)
@@ -117,14 +117,5 @@
{
throw new NotImplementedException();
}
-
- override protected TypeToLoadData GetProviderTypeName()
- {
- return new TypeToLoadData
- {
- assemblyName = "System.Data.DLL",
- className = "SqlConnection",
- };
- }
}
}
\ No newline at end of file
Index: src/DbLinq.Firebird/FirebirdVendor.cs
===================================================================
--- src/DbLinq.Firebird/FirebirdVendor.cs (revision 998)
+++ src/DbLinq.Firebird/FirebirdVendor.cs (working copy)
@@ -201,14 +201,5 @@
}
return outParamValues;
}
-
- override protected TypeToLoadData GetProviderTypeName()
- {
- return new TypeToLoadData
- {
- assemblyName = "FirebirdSql.Data.FirebirdClient.DLL",
- className = "FbConnection",
- };
- }
}
}
Index: src/DbLinq.Ingres/IngresVendor.cs
===================================================================
--- src/DbLinq.Ingres/IngresVendor.cs (revision 998)
+++ src/DbLinq.Ingres/IngresVendor.cs (working copy)
@@ -249,14 +249,5 @@
}
return outParamValues;
}
-
- override protected TypeToLoadData GetProviderTypeName()
- {
- return new TypeToLoadData
- {
- assemblyName = "Ingres.Client.DLL",
- className = "IngresConnection",
- };
- }
}
}
Index: src/DbLinq.Sqlite/SqliteVendor.cs
===================================================================
--- src/DbLinq.Sqlite/SqliteVendor.cs (revision 998)
+++ src/DbLinq.Sqlite/SqliteVendor.cs (working copy)
@@ -203,14 +203,5 @@
}
return outParamValues;
}
-
- override protected TypeToLoadData GetProviderTypeName()
- {
- return new TypeToLoadData
- {
- assemblyName = "System.Data.SQLite.DLL",
- className = "SQLiteConnection",
- };
- }
}
}
Index: src/DbLinq/Vendor/Implementation/Vendor.cs
===================================================================
--- src/DbLinq/Vendor/Implementation/Vendor.cs (revision 998)
+++ src/DbLinq/Vendor/Implementation/Vendor.cs (working copy)
@@ -162,72 +162,20 @@
}
/// <summary>
- /// used during DataContext ctor -
- /// - to ask specific DLL and class to load an IDbConnection object from
- /// </summary>
- /// <returns></returns>
- protected abstract TypeToLoadData GetProviderTypeName();
-
- /// <summary>
/// called from DataContext ctor, which needs to create an IDbConnection, given an IVendor
/// </summary>
public IDbConnection CreateDbConnection(string connectionString)
{
- TypeToLoadData typeToLoad = GetProviderTypeName();
- string assemblyToLoad = typeToLoad.assemblyName; //e.g. "System.Data.SQLite.DLL",
- Assembly assy;
- try
- {
- //TODO: check if DLL is already loaded?
- assy = Assembly.LoadFrom(assemblyToLoad);
- }
- catch (Exception ex)
- {
- //TODO: add proper logging here
- Console.WriteLine("DataContext ctor: Assembly load failed for " + assemblyToLoad + ": " + ex);
- throw ex;
- }
- Type[] STRING_PARAM = new Type[] { typeof(string) };
+ var reConnectionType = new System.Text.RegularExpressions.Regex(@"DbLinqConnectionType=([^;]+)");
+ if (!reConnectionType.IsMatch(connectionString))
+ throw new ArgumentException("No DbLinqConnectionType parameter found. " +
+ "Please specify the assembly qualified type name to use for the Connection Type.",
+ "connectionString");
- //find IDbProvider class in this assembly:
- var ctors = (from mod in assy.GetModules()
- from cls in mod.GetTypes()
- where cls.GetInterfaces().Contains(typeof(IDbConnection))
- let ctorInfo = cls.GetConstructor(STRING_PARAM)
- where ctorInfo != null
- select ctorInfo).ToList();
- if (ctors.Count == 0)
- {
- string msg = "Found no IVendor class in assembly " + assemblyToLoad + " having a string ctor";
- throw new ArgumentException(msg);
- }
- else if (ctors.Count > 1)
- {
- string msg = "Found more than one IVendor class in assembly " + assemblyToLoad + " having a string ctor";
- throw new ArgumentException(msg);
- }
- ConstructorInfo ctorInfo2 = ctors[0];
-
- object iDbConnObject;
- try
- {
- iDbConnObject = ctorInfo2.Invoke(new object[] { connectionString });
- }
- catch (Exception ex)
- {
- //TODO: add proper logging here
- Console.WriteLine("DataContext/Vendor: Failed to invoke IDbConnection ctor " + ctorInfo2.Name + ": " + ex);
- throw ex;
- }
- var connection = (IDbConnection)iDbConnObject;
- return connection;
+ var match = reConnectionType.Match(connectionString);
+ string connectionType = match.Groups[1].Value;
+ connectionString = reConnectionType.Replace(connectionString, "");
+ return (IDbConnection)Activator.CreateInstance(Type.GetType(connectionType), connectionString);
}
-
- // TODO: update, this is obsolete
- public class TypeToLoadData
- {
- public string assemblyName;
- public string className;
- }
}
}
Index: src/DbLinq.PostgreSql/PgsqlVendor.cs
===================================================================
--- src/DbLinq.PostgreSql/PgsqlVendor.cs (revision 998)
+++ src/DbLinq.PostgreSql/PgsqlVendor.cs (working copy)
@@ -228,14 +228,5 @@
}
return outParamValues;
}
-
- override protected TypeToLoadData GetProviderTypeName()
- {
- return new TypeToLoadData
- {
- assemblyName = "Npgsql.DLL",
- className = "NpgsqlConnection",
- };
- }
}
}
Index: src/DbLinq.Oracle/OracleVendor.cs
===================================================================
--- src/DbLinq.Oracle/OracleVendor.cs (revision 998)
+++ src/DbLinq.Oracle/OracleVendor.cs (working copy)
@@ -86,14 +86,5 @@
protected override string ConnectionStringDatabase { get { return null; } }
protected override string ConnectionStringServer { get { return "data source"; } }
-
- override protected TypeToLoadData GetProviderTypeName()
- {
- return new TypeToLoadData
- {
- assemblyName = "Oracle.DataAccess.DLL",
- className = "OracleConnection",
- };
- }
}
}
Index: src/DbLinq.MySql/MySqlVendor.cs
===================================================================
--- src/DbLinq.MySql/MySqlVendor.cs (revision 998)
+++ src/DbLinq.MySql/MySqlVendor.cs (working copy)
@@ -288,15 +288,5 @@
}
return outParamValues;
}
-
- override protected TypeToLoadData GetProviderTypeName()
- {
- return new TypeToLoadData
- {
- assemblyName = "MySql.Data.DLL",
- className = "MySqlConnection",
- };
- }
-
}
}