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);
}
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'm going through the mongoDB Driver Documentation Quick Tour for the first time. Specifically the 2.4 version.
I've created a fresh mongodb instance at the 192.168.1.50 address, and it appears to be running correctly.
The MongoDB documentation gives the following example:
var client = new MongoClient("mongodb://192.168.1.50:27017");
#It's ok if the database doesn't yet exist. It will be created upon first use
var database = client.GetDatabase("testDB");
#It’s ok if the collection doesn’t yet exist. It will be created upon first use.
var collection = database.GetCollection<BsonDocument>("testCollection");
However, when I go on my server, and I enter the mongo console
mongo
And I list the databases using
show dbs
The output is only
admin 0.000GB
local 0.000GB
Is there anything else I should have done to make this work? I'm getting no errors on try/catch, and it appears to be running fine.
Troubleshooting
So far I've confirmed that mongodb is running by using the following:
netstat -plntu
Shows mongod running on 27017 in the LISTEN state.
I'd also be interested in knowing if there's a way on the mongodb server to view live connections, so I could see if it were actually successfully connecting.
Well the problem is that you need to create almost one collection in order to persist the created database (weird right?) i tested it with robomongo and works in that way.
The problem is that GetCollection method is not creating the target collection, you can try with this code:
static void Main(string[] args)
{
var client = new MongoClient("mongodb://192.168.1.50:27017");
//# It's ok if the database doesn't yet exist. It will be created upon first use
var database = client.GetDatabase("test");
//# It’s ok if the collection doesn’t yet exist. It will be created upon first use.
string targetCollection = "testCollection";
bool alreadyExists = database.ListCollections().ToList().Any(x => x.GetElement("name").Value.ToString() == targetCollection);
if (!alreadyExists)
{
database.CreateCollection(targetCollection);
}
var collection = database.GetCollection<BsonDocument>(targetCollection);
}
It turns out that a method I had found on how to set multiple bindIp's was incorrect. The problem wasn't with the C# at all. I found the solution here
In case that ever goes away, here's the current settings I had to follow for multiple ip's
edit file /etc/mongod.conf
Wrap the comma-separated-Ips with brackets
bindIp = [127.0.0.1, 192.168.184.155, 96.88.169.145]
My original code worked fine, I just didn't have the brackets on the bindIp.
all.
Here is my code.
private void FillData(DataTable data, FilterModel filter){
var cmdStr = MySqlCmdGenerator.Generate(filter);
using (var cmd = new SqlCommand(cmdStr, connection_))
using (var da = new SqlDataAdapter(cmd)){
da.Fill(data);
}
}
public DataTable GetData(IEnumerable<FilterModel> filters){
var data = new DataTable("mydata");
foreach (var filter in filters){
FillData(data);
}
return data;
}
It's a very simple code, which just use SqlDataAdapter to Fill datatable according to the filters.
The problem is that sometimes GetData method returns empty datatable.
First I execute the generated query on SQL Server Management Studio, and it returns correct result (it contains about 100,000 records).
Then I have used Sql Server Profiler to profile what happened in server, and get some errors:
Sort Warnings
RPC:Completed (TextData: Query with a given filter)
Hash Warning
Sort Warnings
RPC:Completed (TextData: Query with a given filter)
User Error Message (TextData: The statement has been terminated.)
Attention
Audit Logout
RPC:Completed (TextData: sp_reset_connection)
(occurs in this order)
After google the error but I could not figure out what is exactly happen in server and application.
Any advice will be appreciated.
Thanks!
Differences between results from a .NET application and those from SQL Server Management Studio are often due to different configuration of ANSI settings for the SQL Server connection.
This assumes you've eliminated the obvious error causes, e.g. you're inadvertently connection to different databases from the two environments.
You can see the settings used by SQL Server Management Studio in Tools / Options / Query Execution / SQL Server / ANSI. On my installation they default to:
SET ANSI_NULL_DFLT_ON ON
SET ANSI_PADDING ON
SET ANSI_NULLS ON
I suggest you try switching these OFF one by one in Management Studio to attempt to reproduce the configuration used by .NET. Once you understand what's happening, you can do one of:
Add SET statements to your .NET query
Modify your query so it isn't dependent on these settings (may need to add ISNULL or explicit tests for NULL).
I have a C# .NET WinForms application that uses Crystal Reports.
Crystal reports run fine on both x32 and x64 systems with the exception of reports containing subreports. Any report containing a subreport fails with the wonderful: "Log on failed" at ...VerifyDatabase() but only on x64 systems.
I have seen and fixed this problem in the past by unchecking Verify Database on every print, making sure the no data is being saved with the report and ensuring the correct driver and connection methods are being used in the designer. This problem is not going away and seems to only be affecting reports with subreports.
All projects in the solution are set to build to x32.
The x64 systems have the CR 32bit runtime installed.
The SQL Native Client is also installed.
I have tried many different combinations of report preparations steps like not verifying the database, not refreshing the report, verifying and not refreshing, refreshing and not verifying... it goes on and on.
Here is the current preparation method being used:
private T GetReport<T>() where T: ReportDocument, new()
{
var report = new T();
var connectionStringBuilder
= new SqlConnectionStringBuilder(this.ConnectionString);
var connectionInfo = new ConnectionInfo
{
DatabaseName = connectionStringBuilder.InitialCatalog,
UserID = connectionStringBuilder.UserID,
Password = connectionStringBuilder.Password,
ServerName = connectionStringBuilder.DataSource
};
Action<ReportDocument, bool, bool> setConnection = (document, verify, refresh) =>
{
document.DataSourceConnections.Clear();
document.DataSourceConnections[0].SetConnection(
connectionStringBuilder.DataSource,
connectionStringBuilder.InitialCatalog,
connectionStringBuilder.UserID,
connectionStringBuilder.Password
);
document.DataSourceConnections[0].IntegratedSecurity = false;
/*
foreach (Table table in document.Database.Tables)
{
var tableLogOnInfo = table.LogOnInfo;
tableLogOnInfo.ConnectionInfo = connectionInfo;
table.ApplyLogOnInfo(tableLogOnInfo);
}
* */
//document.SetDatabaseLogon(connectionInfo.UserID, connectionInfo.Password, connectionInfo.ServerName, connectionInfo.DatabaseName);
if (verify)
document.VerifyDatabase();
if (refresh)
document.Refresh();
};
for (var index = 0; index < report.Subreports.Count; index++)
{
var subreportName = report.Subreports[index].Name;
var subreport = report.OpenSubreport(subreportName);
setConnection(subreport, false, false);
}
setConnection(report, true, true);
return report;
}
SOLVED: I have gotten the report to work. I am not sure what part of this solution actually solved the problem but these are the steps I took.
I checked the data source per aMazing's suggestion below. (It was already OLE DB)
I removed all referenced to Crystal Reports in all projects in the solution.
I re-added the Crystal Reports references and made sure all the references were the same version and made sure all references were set to 'Specific Version' = True.
I set 'Copy Local' to True on the CR references on one project in the solution.
I changed the call to the **setConnection** to not verify.
I un-commented foreach table.ApplyLogOnInfo(tableLogOnInfo) section.
I'm not sure why it works now but it does. The table.ApplyLogOnInfo was un-commented in many of the permutations I tried earlier. Maybe I never hit this specific combination... but I don't care at this point.
SOLVED: I have gotten the report to work. I am not sure what part of this solution actually solved the problem but these are the steps I took.
I checked the data source per aMazing's suggestion below. (It was already OLE DB)
I removed all referenced to Crystal Reports in all projects in the solution.
I re-added the Crystal Reports references and made sure all the references were the same version and made sure all references were set to 'Specific Version' = True.
I set 'Copy Local' to True on the CR references on one project in the solution.
I changed the call to the **setConnection** to not verify.
I un-commented foreach table.ApplyLogOnInfo(tableLogOnInfo) section.
I'm not sure why it works now but it does. The table.ApplyLogOnInfo was un-commented in many of the permutations I tried earlier. Maybe I never hit this specific combination... but I don't care at this point.
Because I couldnt add a comment, this was the only way I could reply.
What SQL server are you using? I had something similar before.
Check the following on both report and sub report:
1) Right Click Datasource Properties
2) Select Set Datasource Location
3) On the connetion that the report is using, click expand Properties
4) Confirm that the Database Type = OLE DB (ADO) and Provider is SQLOLEDB.
That fixed my problem. I had set it to SQLNative Client before which was failing.
Hope it helps.
Thanks
Check if you have an Access database or any other 32 bit datasource in any of the subreports.
I had this same problem recently. I found the cause to be not setting the datasource, which in my case was due to an incorrect if statement, meaning the following line was not running:
repdoc.Subreports["SubReportName.rpt"].SetDataSource((DataTable)MyDataTable);
Hope this is of use.
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.