|
|
Comments and Discussions
|
|
 |

|
Hi, there is an exception that is simply ignored causing SQL errors not to be reported. This leads to "Unable to ..." error. It took me 4 hours to find the problem until I had to debug through the source code. If you just add tracing for SQL exceptions that would be great. The code that needs to be added is in StoredProcedure.cs (lowest 2 lines of this code): public static StoredProcedure Inspect( SqlConnection connection, string name) { // get a collection mapping user-defined data types to their // base-equivalents. StringDictionary typeMap = ReadUserDefinedDataTypes(connection); // get parameter and result set metadata StoredProcedurePrototype prototype = InspectPrototype(connection, typeMap, name); StoredProcedureResultSetColumns resultSet = null; try { resultSet = InspectResultSet(connection, name, prototype.Parameters); } catch(Exception e) { Console.WriteLine(); // added these 2 lines Console.WriteLine(e.Message); resultSet = null; }
|
|
|
|

|
this is some great stuff thanks for sharing this, it looks like this will save me a bunch of time.
is there anyway of providing a sample application using the Generated dlls, xsd, etc... It would help me and others out greatly.
thanks.
|
|
|
|

|
FYI, I cannot get this to work with Oracle 9i.
Here is what happens.
I run the project, it prompts me for database information, I fill in the database dialog, I press "Test Connection", it says "OK", then the Generator program complains that I must "choose a database too", I go back to the database info dialog, I use the same UID and PWD and I try to list the initial catalog to use and it says "invalid parameter", and I am stuck.
It does the same thing for OLEDB and Oracle provider selection.
(Note that I can connect to this Oracle instance using other programs such as TOAD, MyGeneration, SQL Navigator. When I supply the same credentials, those programs can find the database information just fine.)
Any ideas?
Please advise.
Thank you.
--Mark
|
|
|
|

|
L--
Thank you very much for a very nice tool.
Will this work for Oracle 9i?
(If not, can you suggest something?)
Please adivse.
Thank you.
--Mark
|
|
|
|
|

|
I ran the demo and generated the code, the assembly and the xsd file. Now I can call one of the wrapper functions but I'm not sure how to define the table attribute that it takes.
I used the xsd.exe tool to generate a class from the xml shema but that's where I get lost.
What do I do next to make this useful tool work?
Can anybody help? What am I missing?
Iryx
|
|
|
|

|
Hello
I tried the example program to connect to a SQL Server 2000 database, but it failed and quit with the following exception error.
An unhandled exception of type 'System.Data.SqlClient.SqlException' occurred in system.data.dll
Additional information: System error.
|
|
|
|

|
In one of my Stored Procs I'm writing to a table with a PK field that has IDENTITY. When I try to use the code generated by DBHelper it asks me for a "ref int" value for this field.
How do I tell the SP that the field is the IDENTITY and it autonumbers for me?
I cant figure out what to pass to the method to get it to work.
Thanks
Dan B
|
|
|
|

|
I have a stored procedure that takes an image as a parameter. I had used you tool to generate the class to execute this stored procedure. It was working fine if the image was less than 65,534 bytes. However when it went beyond that size I was getting an "Error: 17805, Severity: 20, State: 3 Invalid buffer received from client". It seems that your tool used the sql type of SqlDbType.VarBinary in the paremeters list instead of using SqlDbType.Image. Once I changed the type the code worked fine.
andy
|
|
|
|

|
Since INFORMATION_SCHEMA.ROUTINES isn't supported in 7.0, I changed affected code to:
select [name] from sysobjects where xtype = 'P' order by [name]
and it works (at least I think it does!)
-Vorn
|
|
|
|

|
Dude, if you've not got money or a job - then you sure do seem to have alot of industry knowledge and some pretty damn cool coding skills!
Personally I wouldn't go near any SQL unless my job requires it, which now it does.
Thanks for your article, as always well written and understandable.
/**********************************
Paul Evans, Dorset, UK.
Personal Homepage "EnjoySoftware" @
http://www.enjoysoftware.co.uk/
**********************************/
|
|
|
|

|
Hello, this is a very usefull tool, especially if output and return parameters (@RETURN_VALUE) are supported. I added this for C# to the source. I think the method SP::Generate is the only updated Source. The resulting methods are like this: public static int AddCompany( System.Data.SqlClient.SqlConnection connection, System.Data.DataTable table, ref int RETURN_VALUE_param, ref int CompID_param, string CompName_param, string CompShortName_param, string CompDesc_param ) Output and return parametes has the modifier "ref". The parameter table can be "null". This is usefull for the most SP's. Enjoy Andreas Because i can't post the complete Project as attachment here the method SP::Generate. public CodeNamespace Generate(string ns, string classname) { CodeNamespace cns = new CodeNamespace(ns); cns.Imports.Add( new CodeNamespaceImport("System")); cns.Imports.Add( new CodeNamespaceImport("System.Data")); cns.Imports.Add( new CodeNamespaceImport("System.Data.SqlClient")); CodeTypeDeclaration cclass = new CodeTypeDeclaration(classname); cclass.IsClass = true; foreach(StoredProc sp in allsp) { if (sp.Create) { //SqlCommand com = sp.GetCommand(); //generate the code // if (sp.Parameters.Contains("@RETURN_VALUE")) // sp.Parameters.Remove(sp.Parameters["@RETURN_VALUE"]); CodeMemberMethod method = new CodeMemberMethod(); method.Name = sp.Name/*.Replace(" ","_")*/; //gotta figure out how to handle spaces method.ReturnType = new CodeTypeReference("System.Int32"); method.Attributes = MemberAttributes.Public | MemberAttributes.Static; CodeParameterDeclarationExpression connpar = new CodeParameterDeclarationExpression(typeof(SqlConnection), "connection"); method.Parameters.Add( connpar); method.Parameters.Add( new CodeParameterDeclarationExpression(typeof(DataTable), "table")); //method.Parameters.Add( new CodeParameterDeclarationExpression(typeof(bool), "filltable")); method.Statements.Add( new CodeVariableDeclarationStatement( typeof(SqlCommand), "cmd", new CodeObjectCreateExpression(typeof(SqlCommand)))); method.Statements.Add( new CodeVariableDeclarationStatement(typeof(int), "result", new CodePrimitiveExpression(0))); CodeSnippetExpression cmdexp = new CodeSnippetExpression("cmd"); method.Statements.Add( new CodeAssignStatement( new CodePropertyReferenceExpression( cmdexp, "Connection"), new CodeVariableReferenceExpression("connection") )); method.Statements.Add( new CodeSnippetExpression("cmd.CommandText = \"" + sp + "\"")); method.Statements.Add( new CodeSnippetExpression("cmd.CommandType = CommandType.StoredProcedure")); foreach (SqlParameter par in sp.Parameters) { CodeParameterDeclarationExpression cpar = new CodeParameterDeclarationExpression( /*(par.SqlParameter.IsNullable) ? typeof(object) : */ TypeMapping.Mapping[par.SqlDbType], par.ParameterName.Replace("@","") + "_param"); // Ist so nicht OK // if (par.Direction == ParameterDirection.InputOutput) // cpar.Direction = FieldDirection.Ref; // if (par.Direction == ParameterDirection.Output) // cpar.Direction = FieldDirection.Out; if (par.Direction == ParameterDirection.InputOutput || par.Direction == ParameterDirection.Output ) cpar.Direction = FieldDirection.Ref; else if ( par.Direction == ParameterDirection.Input ) cpar.Direction = FieldDirection.In ; else if ( par.Direction == ParameterDirection.ReturnValue ) //cpar.Direction = FieldDirection.Out; // out int xxx cpar.Direction = FieldDirection.Ref; // ref int xxx method.Parameters.Add(cpar); method.Statements.Add( //new CodeMethodInvokeExpression( //new CodePropertyReferenceExpression( new CodeVariableReferenceExpression("cmd"), //"Parameters"), "Add", new CodeSnippetExpression( String.Format("cmd.Parameters.Add(\"{0}\", SqlDbType.{1}).Value = {2}", par.ParameterName, par.SqlDbType, par.ParameterName.Replace("@","") + "_param") )); if ( par.Direction == ParameterDirection.Output || par.Direction == ParameterDirection.InputOutput ) { method.Statements.Add( new CodeSnippetExpression( String.Format( "cmd.Parameters[\"{0}\"].Direction = ParameterDirection.Output", (string)par.ParameterName ) ) ); } else if ( par.Direction == ParameterDirection.ReturnValue ) { method.Statements.Add( new CodeSnippetExpression( String.Format( "cmd.Parameters[\"{0}\"].Direction = ParameterDirection.ReturnValue", (string)par.ParameterName ) ) ); } } method.Statements.Add( new CodeMethodInvokeExpression( new CodeVariableReferenceExpression("connection"), "Open")); CodeTryCatchFinallyStatement trycatch = new CodeTryCatchFinallyStatement(); CodeConditionStatement choice = new CodeConditionStatement( new CodeBinaryOperatorExpression( new CodeVariableReferenceExpression("table"), CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression(null) )); choice.TrueStatements.Add( new CodeVariableDeclarationStatement(typeof(SqlDataReader), "reader", new CodeMethodInvokeExpression( new CodeVariableReferenceExpression("cmd"), "ExecuteReader") )); CodeConditionStatement tabletest = new CodeConditionStatement( new CodeBinaryOperatorExpression( new CodeSnippetExpression("table.Columns.Count"), CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(0) )); tabletest.TrueStatements.Add( new CodeAssignStatement( new CodeVariableReferenceExpression("table.TableName"), new CodeSnippetExpression("\"" + sp + "\"") )); CodeIterationStatement forfield = new CodeIterationStatement( new CodeVariableDeclarationStatement(typeof(int), "i", new CodePrimitiveExpression(0)), new CodeBinaryOperatorExpression( new CodeVariableReferenceExpression("i"), CodeBinaryOperatorType.LessThan, new CodePropertyReferenceExpression( new CodeVariableReferenceExpression("reader"),"FieldCount")), new CodeSnippetStatement("i = i + 1")); forfield.Statements.Add( new CodeVariableDeclarationStatement( typeof(Type), "type", new CodeMethodInvokeExpression( new CodeVariableReferenceExpression("reader"), "GetFieldType", new CodeVariableReferenceExpression("i")))); forfield.Statements.Add( new CodeVariableDeclarationStatement( typeof(string), "name", new CodeMethodInvokeExpression( new CodeVariableReferenceExpression("reader"), "GetName", new CodeVariableReferenceExpression("i")))); forfield.Statements.Add( new CodeMethodInvokeExpression( new CodePropertyReferenceExpression( new CodeVariableReferenceExpression("table"), "Columns"), "Add", new CodeVariableReferenceExpression("name"), new CodeVariableReferenceExpression("type"))); tabletest.TrueStatements.Add(forfield); //tabletest.TrueStatements.Add( new CodeSnippetExpression("reader.Close()")); //tabletest.TrueStatements.Add( new CodeMethodReturnStatement( // new CodeVariableReferenceExpression("table.Columns.Count") // )); choice.TrueStatements.Add(tabletest); choice.TrueStatements.Add( new CodeMethodInvokeExpression( new CodeVariableReferenceExpression("table"), "Clear")); CodeIterationStatement whileread = new CodeIterationStatement( //not sure how to handle this in VB and JS new CodeSnippetStatement(""), new CodeMethodInvokeExpression( new CodeVariableReferenceExpression("reader"), "Read"), //not sure how to handle this in VB and JS new CodeSnippetStatement("result = result + 1")); whileread.Statements.Add( new CodeVariableDeclarationStatement(typeof(DataRow), "row", new CodeMethodInvokeExpression( new CodeVariableReferenceExpression("table"), "NewRow"))); whileread.Statements.Add( new CodeVariableDeclarationStatement(typeof(object[]), "rowdata", new CodeArrayCreateExpression(typeof(object), new CodePropertyReferenceExpression( new CodeVariableReferenceExpression("reader"), "FieldCount")))); whileread.Statements.Add( new CodeMethodInvokeExpression( new CodeVariableReferenceExpression("reader"), "GetValues", new CodeVariableReferenceExpression("rowdata"))); whileread.Statements.Add( new CodeAssignStatement( new CodePropertyReferenceExpression( new CodeVariableReferenceExpression("row"),"ItemArray"), new CodeVariableReferenceExpression("rowdata"))); whileread.Statements.Add( new CodeMethodInvokeExpression( new CodePropertyReferenceExpression( new CodeVariableReferenceExpression("table"), "Rows"), "Add", new CodeVariableReferenceExpression("row"))); choice.TrueStatements.Add(whileread); foreach (SqlParameter par2 in sp.Parameters) { if ( par2.Direction == ParameterDirection.Output || par2.Direction == ParameterDirection.InputOutput || par2.Direction == ParameterDirection.ReturnValue ) { choice.TrueStatements.Add( new CodeSnippetExpression( String.Format( "{0} = ({1})cmd.Parameters[\"{2}\"].Value", (par2.ParameterName.Replace("@","") + "_param"), TypeMapping.Mapping[par2.SqlDbType].ToString(), // Mappt zu .net Framework Typ z.B. System.In32 (string)par2.ParameterName ) ) ); } } choice.TrueStatements.Add( new CodeMethodInvokeExpression( new CodeVariableReferenceExpression("reader"), "Close")); choice.FalseStatements.Add( new CodeAssignStatement( new CodeVariableReferenceExpression("result"), new CodeMethodInvokeExpression( new CodeVariableReferenceExpression("cmd"), "ExecuteNonQuery") )); foreach (SqlParameter par2 in sp.Parameters) { if ( par2.Direction == ParameterDirection.Output || par2.Direction == ParameterDirection.InputOutput || par2.Direction == ParameterDirection.ReturnValue ) { choice.FalseStatements.Add( new CodeSnippetExpression( String.Format( "{0} = ({1})cmd.Parameters[\"{2}\"].Value", (par2.ParameterName.Replace("@","") + "_param"), TypeMapping.Mapping[par2.SqlDbType].ToString(), // Mappt zu .net Framework Typ z.B. System.In32 (string)par2.ParameterName ) ) ); } } trycatch.TryStatements.Add(choice); CodeCatchClause catchclause = new CodeCatchClause("ex", new CodeTypeReference("SqlException")); catchclause.Statements.Add( new CodeThrowExceptionStatement( new CodeVariableReferenceExpression("ex"))); trycatch.CatchClauses.Add( catchclause); trycatch.FinallyStatements.Add( new CodeMethodInvokeExpression( new CodeVariableReferenceExpression("connection"), "Close")); method.Statements.Add(trycatch); method.Statements.Add( new CodeMethodReturnStatement( new CodeVariableReferenceExpression("result"))); cclass.Members.Add(method); } } cns.Types.Add(cclass); return cns; } Andreas Gratz
|
|
|
|

|
i have a database with 97 stored procedures. all of them are included in the generated c#-file,
but only 6 of them (they seem to be randomly choosen) are in the xsd-file.
whats going wrong ?
is there a limitation i dont know ?
ciao,
uwe
|
|
|
|
|

|
I´m creating a similar project... but it doesn´t create a class (it creates the code necessary to create the parameters) and it was created as an VS.NET Add-in. Don´t know if I should post it now...
BTW, nice article, very usefull ! Got my five !
Mauricio Ritter - Brazil
Sonorking now: 100.13560 MRitter
"Th@ langwagje is screwed! It has if's but no end if's!! Stupid php cant even do butuns on forms! VISHAUL BASICS ARE THE FUTSHURE!" - Simon Walton
|
|
|
|

|
Leppie,
This is very nice work, but there is room for improvement (isn't there always ). In particular, it would be nice if you UI would allow the user to specify which procedures were execute only types (not returning records, but only a records affected cout, meant to be 'Cmd.ExecuteNoRecords' targets), also the generated code is broken if one or more of the parameters are output parameters, Since yuuo build the command with all the parameters set to the default (ParameterDirection.Input)...
It might help to factor the gernerated code a bit:
For each SP, build a method to construct the command object: public static SqlCommand BuildSP(string ProcName){}
One for getting Data: public static int SP_GetData(SqlCommand cmd, SqlConnection connection, System.Data.DataTable table, SomeDataType p1Val,ref SomeValueType p2,...){ ... return results;} (buld the DataTable pretty much as you do...maybe some special handling for dbNulls, set the values for the parameters that were output types - pass them in as ref Valuetype so the proc can set the values)
and one for execute: public static int SP_Execute(SqlCommand cmd, SqlConnection connection,SomeDataType param1val,...){ ....return RecordsAffected;}
It might also be desirable to let the caller specify the CommandBehavior and perhaps Transaction.. many times you don't want to close the connection immediately, overloads on each of the methods could work here...
Also, either put the SqlDataReaders in a using{} block or a try-catch-finally (close the reader in finally...). Failing to close the reader because an exception took you out of scope creates some really ugly problems...
Keep up the Good work!
Rob
|
|
|
|

|
I rated this article 2 by mistake. It deserves more. I wanted to get to the second page...
|
|
|
|

|
Nice job! - Before it becomes really usable you should add DBNulls to your application
|
|
|
|

|
... but I just finished a project where a couple of SPs required 30 parametres.
Your code would have saved my now damned soul
Will try it out on the next project though, thanks
Paul Watson Bluegrass Cape Town, South Africa Colin Davies wrote:
...can you imagine a John Simmons stalker !
|
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
|
This a small tool that will generate static methods in a class that acts as wrapper for SQL stored procedures. It either outputs a source file or a compiled assembly. Also supports automatic DataSet generation.
| Type | Article |
| Licence | BSD |
| First Posted | 17 Nov 2002 |
| Views | 303,362 |
| Bookmarked | 140 times |
|
|