Sometimes I really start wondering what's going on in my sourcecode:
I'm trying to connect to PostGres 9.0 using npgsql 2.0.11.0, which I'm damn sure I already did, but right now, my program throws a NotSupportedException as it steps into the following :
ISessionFactory sf = Fluently.Configure()
.Database(PostgreSQLConfiguration.PostgreSQL82
.ConnectionString(c => c
.Host("localhost")
.Port(5432)
.Database("cw")
.Username("cw")
.Password("mypass")))
.Mappings(x => x.FluentMappings.AddFromAssemblyOf<MyMapping>())
.BuildSessionFactory();
The Stacktrace is quite neat to look at: Just one line.
at NHibernate.Dialect.Dialect.GetDataBaseSchema(DbConnection connection) in d:\CSharp\NH\nhibernate\src\NHibernate\Dialect\Dialect.cs:Line 718.
I tried transcribing this to the following:
ISessionFactory sf = Fluently.Configure()
.Database(PostgreSQLConfiguration.PostgreSQL82
.ConnectionString(c => c.Is("Server=localhost;Port=5432;Database=cw;User Id=cw;Password=myPass;")))
.Mappings(x => x.FluentMappings.AddFromAssemblyOf<CardTemplateMapping>())
.BuildSessionFactory();
Still, the result's the same. Anybody had similar issues or - even better - a fix?
I guess I'll end up holding a record for the most self-answered questions.
It needed the hbm2ddl.keywords property set to none. Now it works like a charm.
Cheers!
.Database(PostgreSQLConfiguration.PostgreSQL82
.Raw("hbm2ddl.keywords","none"));
See that you already found a solution. So just for some background:
The "none" will disable any operation regarding RDBMS KeyWords.
And the Keywords is available for MsSQL, Oracle, Firebird, MsSqlCe, MySQL, SQLite, SybaseAnywhere.
Since Postgress is not in the list it has to be set to None.
There is som info on it here: Quoting column names with NHibernate and PostgreSQL
Related
Is there a way to dump the generated sql to the Debug log or something? I'm using it in a winforms solution so the mini-profiler idea won't work for me.
I got the same issue and implemented some code after doing some search but having no ready-to-use stuff. There is a package on nuget MiniProfiler.Integrations I would like to share.
Update V2: it supports to work with other database servers, for MySQL it requires to have MiniProfiler.Integrations.MySql
Below are steps to work with SQL Server:
1.Instantiate the connection
var factory = new SqlServerDbConnectionFactory(_connectionString);
using (var connection = ProfiledDbConnectionFactory.New(factory, CustomDbProfiler.Current))
{
// your code
}
2.After all works done, write all commands to a file if you want
File.WriteAllText("SqlScripts.txt", CustomDbProfiler.Current.ProfilerContext.BuildCommands());
Dapper does not currently have an instrumentation point here. This is perhaps due, as you note, to the fact that we (as the authors) use mini-profiler to handle this. However, if it helps, the core parts of mini-profiler are actually designed to be architecture neutral, and I know of other people using it with winforms, wpf, wcf, etc - which would give you access to the profiling / tracing connection wrapper.
In theory, it would be perfectly possible to add some blanket capture-point, but I'm concerned about two things:
(primarily) security: since dapper doesn't have a concept of a context, it would be really really easy for malign code to attach quietly to sniff all sql traffic that goes via dapper; I really don't like the sound of that (this isn't an issue with the "decorator" approach, as the caller owns the connection, hence the logging context)
(secondary) performance: but... in truth, it is hard to say that a simple delegate-check (which would presumably be null in most cases) would have much impact
Of course, the other thing you could do is: steal the connection wrapper code from mini-profiler, and replace the profiler-context stuff with just: Debug.WriteLine etc.
You should consider using SQL profiler located in the menu of SQL Management Studio → Extras → SQL Server Profiler (no Dapper extensions needed - may work with other RDBMS when they got a SQL profiler tool too).
Then, start a new session.
You'll get something like this for example (you see all parameters and the complete SQL string):
exec sp_executesql N'SELECT * FROM Updates WHERE CAST(Product_ID as VARCHAR(50)) = #appId AND (Blocked IS NULL OR Blocked = 0)
AND (Beta IS NULL OR Beta = 0 OR #includeBeta = 1) AND (LangCode IS NULL OR LangCode IN (SELECT * FROM STRING_SPLIT(#langCode, '','')))',N'#appId nvarchar(4000),#includeBeta bit,#langCode nvarchar(4000)',#appId=N'fea5b0a7-1da6-4394-b8c8-05e7cb979161',#includeBeta=0,#langCode=N'de'
Try Dapper.Logging.
You can get it from NuGet. The way it works is you pass your code that creates your actual database connection into a factory that creates wrapped connections. Whenever a wrapped connection is opened or closed or you run a query against it, it will be logged. You can configure the logging message templates and other settings like whether SQL parameters are saved. Elapsed time is also saved.
In my opinion, the only downside is that the documentation is sparse, but I think that's just because it's a new project (as of this writing). I had to dig through the repo for a bit to understand it and to get it configured to my liking, but now it's working great.
From the documentation:
The tool consists of simple decorators for the DbConnection and
DbCommand which track the execution time and write messages to the
ILogger<T>. The ILogger<T> can be handled by any logging framework
(e.g. Serilog). The result is similar to the default EF Core logging
behavior.
The lib declares a helper method for registering the
IDbConnectionFactory in the IoC container. The connection factory is
SQL Provider agnostic. That's why you have to specify the real factory
method:
services.AddDbConnectionFactory(prv => new SqlConnection(conStr));
After registration, the IDbConnectionFactory can be injected into
classes that need a SQL connection.
private readonly IDbConnectionFactory _connectionFactory;
public GetProductsHandler(IDbConnectionFactory connectionFactory)
{
_connectionFactory = connectionFactory;
}
The IDbConnectionFactory.CreateConnection will return a decorated
version that logs the activity.
using (DbConnection db = _connectionFactory.CreateConnection())
{
//...
}
This is not exhaustive and is essentially a bit of hack, but if you have your SQL and you want to initialize your parameters, it's useful for basic debugging. Set up this extension method, then call it anywhere as desired.
public static class DapperExtensions
{
public static string ArgsAsSql(this DynamicParameters args)
{
if (args is null) throw new ArgumentNullException(nameof(args));
var sb = new StringBuilder();
foreach (var name in args.ParameterNames)
{
var pValue = args.Get<dynamic>(name);
var type = pValue.GetType();
if (type == typeof(DateTime))
sb.AppendFormat("DECLARE #{0} DATETIME ='{1}'\n", name, pValue.ToString("yyyy-MM-dd HH:mm:ss.fff"));
else if (type == typeof(bool))
sb.AppendFormat("DECLARE #{0} BIT = {1}\n", name, (bool)pValue ? 1 : 0);
else if (type == typeof(int))
sb.AppendFormat("DECLARE #{0} INT = {1}\n", name, pValue);
else if (type == typeof(List<int>))
sb.AppendFormat("-- REPLACE #{0} IN SQL: ({1})\n", name, string.Join(",", (List<int>)pValue));
else
sb.AppendFormat("DECLARE #{0} NVARCHAR(MAX) = '{1}'\n", name, pValue.ToString());
}
return sb.ToString();
}
}
You can then just use this in the immediate or watch windows to grab the SQL.
Just to add an update here since I see this question still get's quite a few hits - these days I use either Glimpse (seems it's dead now) or Stackify Prefix which both have sql command trace capabilities.
It's not exactly what I was looking for when I asked the original question but solve the same problem.
I try to enable the Bach Size in my SessionFactory:
Fluently.Configure()
.Database(MySQLConfiguration.Standard.AdoNetBatchSize(1)
.ConnectionString("xxx"))
.Mappings(m => m.FluentMappings.AddFromAssembly(...))
.ExposeConfiguration(c => c.SetProperty("adonet.batch_size", "1"))
.BuildSessionFactory();
but when I want to set the value of the batch size:
Session = _sessionFactory.OpenSession();
Session.SetBatchSize(25);
Session.FlushMode = FlushMode.Commit;
I still get that error:
No batch size was defined for the session factory, batching is
disabled. Set adonet.batch_size = 1 to enable batching.
You should use
MySqlClientBatchingBatcherFactory
Thus, something like
Fluently.Configure()
.Database(MySQLConfiguration.Standard
.ConnectionString("xxx"))
.Mappings(m => m.FluentMappings.AddFromAssembly(...))
.ExposeConfiguration(c => c.DataBaseIntegration(prop =>
{
prop.BatchSize = 50;
prop.Batcher<MySqlClientBatchingBatcherFactory>();
}))
.BuildSessionFactory();
should work.
Please see these answers: Fluent NHibernate MySQL batching or MySQL NHibernate Batcher if you had further problems with batching; they show other ways to implement it.
Take into account that NHibernate prior to ¿4.0? did not support (natively) batching when combined with MySQL, and a external package was needed (due to some mysql dependencies). After this version, however, the batcher was included into the main trunk so these answers are still valid.
If you use NHibernate 4+, no problems should arise.
I'm having major difficulties to start off with NHiberante.
Main problems:
Where my hbm.xml files should reside? I create a Mappings folder but I received an error "Could not find xxx.hbm.xml file."
I tried to load the specific class through the dialect cf.AddClass(typeof(xxx)); but it still gives me the same error (the files are marked as embebed resources.
Also I'm having major problems in connection to it. I stopped trying to use the cfg xml file and tried a more direct approach with a library I have here.
Configuration cfg = new Configuration();
cfg.AddClass(typeof(Tag));
ISessionFactory sessions = cfg.BuildSessionFactory();
AgnosticConnectionHandler agch = new AgnosticConnectionHandler("xxx","xxx","geo_biblio","localhost",
5432,DatabaseInstance.PostgreSQL);
ISession sessao = sessions.OpenSession(agch.GetConnection);
ITransaction tx = sessao.BeginTransaction();
Tag tag1 = new Tag();
tag1.NomeTag = "Teste Tag NHibernate!!!";
sessao.Save(tag1);
tx.Commit();
sessao.Close();
Any tips for me? I'm getting the exception in line 2 of this code, and still not sure what to do.
Any help is appreciated. Thanks
If you're starting with nHibernate I think you really should take a look at fluent nhibernate, its way easier do develop and maintain the mapping, it even has an auto-mapping option.
Another option is confORM from Fabio Maulo (nhibernate lead developer), looks like a great tool.
Also, you can take a look at s#arp architecture, you can get some nice ideas from this project.
In short: What is a good method for setting up read-only data access from Silverlight to a MySQL database?
Here are the details of my situation:
I'm currently trying to set up a Silverlight application to present data from a MySQL database. Currently, I need to set-up read-only access to the MySQL database (I may set up other tables for complete CRUD functionality at a later, date, but for these particular tables, I'm only ever going to be concerned with the retrieve aspect).
I tried setting it up using RIA Services (CTP July 2009) with Entity Framework, but I had trouble debugging it and ended up trying to recompile the source code from the MySQL ADO.NET connector in order to install custom DLLs into the GAC. I wasn't able to get any of this stuff to work correctly.
My problem was that I had date values stored as 0000-00-00 in lots of my MySQL tables. The MySQL ADO.NET Connector throws an exception everytime it tries to bring down a row with an invalid date in it. I would try to recompile the connector (see links above), but that's feeling very much like a hack. I would try to update the values in the MySQL database to be within the appropriate spec for dates, but our IT manager (and effectively our DBA) does not want to do it.
I don't mind learning to work with LINQ (LINQ-to-what?), but I want to avoid concatenating my own strings of SQL commands. Because of the Date restrictions, I need a way to specify Case When orders.OrderDate = '0000-00-00' Then '0001-01-01' Else orders.OrderDate End for pretty much every date instance.
I'm especially interested to hear from folks who have worked with .NET and MySQL together. What will work in my situation?
Why has no one suggested using a ORM to hide the mySQL details? Both NHibernate and Subsonic support mySQL. Both are very customisable in how they interact with the database and should allow you to cater for malformed dates.
By using an ORM your data objects are now POCOs, and you can use whatever you want to get the data to the Silverlight client. Vanilla web services or WCF should be fine. RIA services if you want to try out the bleeding edge.
IMHO, this will be simpler than setting up a mysql->php->xml->asp.net->silverlight chain.
My problem was that I had date values stored as 0000-00-00 in lots of my MySQL tables.
Can you just write Select NullIf( SomeDate, '0000-00-00') As SomeDate From SomeTable in your SQL queries? I don't know MySQL, but that's what I would do in T-SQL.
Here is what I did for a similar problem I was facing.
I used php to get data from the MySQL database and turned it into an XML file. I called that file from my silverlight app and used LINQtoXML to parse the data and make it available in my XAML controls. I am not a programmer by trade so maybe there is a better way to do it but this works for my app. Hope this helps. LINQ ROCKS!
Here is a portion of the code:
< ?php
header("Content-type: text/xml");
$grb_hostname = "host";
$grb_database = "dbName";
$grb_username = "dbUser";
$grb_password = "dbPwd";
$grb = mysql_connect($grb_hostname, $grb_username, $grb_password);
mysql_select_db($grb_database, $grb);
$results = mysql_query("SELECT * FROM bursts ORDER BY bursts.id DESC");
$xmlOutput = "<?xml version=\"1.0\"?>\n";
$xmlOutput .= "<grbs>\n";
while($row = mysql_fetch_array($results)) {
$xmlOutput .= "\t<grb id=\"".$row['id']."\" trigger=\"".$row['trigger']."\">\n";
$xmlOutput .= "\t\t<grb_id>".$row['grb_id']."</grb_id>\n";
$xmlOutput .= "\t\t<burst_ra>".$row['burst_ra']."</burst_ra>\n";
$xmlOutput .= "\t\t<burst_dec>".$row['burst_dec']."</burst_dec>\n";
$xmlOutput .= "\t</grb>\n";
}
$xmlOutput .= " < /grbs>"; // no space before /
echo $xmlOutput;
?>
then in my Silverlight I have the following:
private void LoadGrbs()
{
WebClient grbXmlFile = new WebClient();
// Make sure the crossdomainpolicy.xml file exists on the remote server.
grbXmlFile.DownloadStringAsync(new Uri("url_xml_generating_php_file", UriKind.Absolute));
grbXmlFile.DownloadStringCompleted += new DownloadStringCompletedEventHandler(grbsXmlLoaded);
}
private void grbsXmlLoaded(object sender, DownloadStringCompletedEventArgs e)
{
processGrbXml(e.Result);
}
private void processGrbXml(string grbData)
{
XDocument grbs = XDocument.Parse(grbData);
var query = from g in grbs.Descendants("grb")
select new
{
grbId = (string)g.Element("grb_id"),
grbDec = (string)g.Element("burst_dec")
};
foreach (var grb in query)
{
grbListbox.Items.Add(grb.grbId);
}
}
grbListbox is a Listbox control in my Silverlight app.
You should use RIA Services, the newest version came out last week, and it's included in the silverlight 4 beta now.
http://silverlight.net/getstarted/silverlight-4-beta/
You don't have to use the entity framework with RIA, there are other options. We do, but we use SQL Server so that might not be your favorite.
They have changed the errors some in the new RIA Stuff, so I'd recommend taking a 2nd look. Here's Brad Abrams' example from last week:
http://microsoftpdc.com/Sessions/CL21
Finally, if you're having a lot of trouble debugging, you could take a look at Fiddler. It's a program that watches the traffic and it can display you the errors you're having in a more obvious fashion.
Making my first steps with NHibernate, I'm trying to have it creating my Tables automatically from the hbm files. The database backend is SQL Server 2008 Developer Edition.
This is the common sample code I see in NHibernate Tutorials:
var cfg = new Configuration();
cfg.Configure();
cfg.AddAssembly(typeof(Posting).Assembly);
new SchemaExport(cfg).Execute(false,true,false,false);
Sadly, this does not work. I have set show_sql to true, and it does not print out any statement. Looking at SQL profiler I see my Application connecting to the DB, but then doing nothing.
I can fix that by changing the first parameter ("script") to true:
new SchemaExport(cfg).Execute(true,true,false,true);
I don't understand why. The parameters of SchemaExport are sadly not really explained (also not the difference between .Create and .Execute), and I would like to find out what this parameter does, and why it's not needed i.e. when using SQL Compact Edition (that works also when script is false)
The SchemaExport is part of the Hbm2Ddl utility which is really separate from NHibernate functionality. It does not use "show_sql" which is used while NHibernate is running only.
To get a copy of the schema you create you use .SetOutputFile(filename)
This is the method I use when I wish to create a new database.
I get a formatted schema in MyDDL.sql file and the database is built from the schema:
private void BuildSchema(Configuration config)
{
new SchemaExport(config)
.SetOutputFile(_fileName + "MyDDL.sql")
.Execute(true /*script*/, true /*export to db*/,
false /*just drop*/, true /*format schema*/);
}
SchemaExport.Create is just a shortcut to Schema.Execute with the just drop false and format true.
public void Create(bool script, bool export)
{
Execute(script, export, false, true);
}