Specifying SqlString length for a CLR stored procedure - c#

I'm writing stored procedures in C# at the moment and I've run into a problem with the size of a parameter.
So I've created a project in VS 2008 and created several stored procedures which all look a bit like this:
public partial class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void SaveProgress(... SqlString logpart, ...)
{
...stuff...
}
}
Now because I've not specified anything else, when I deploy this to a database, the CREATE DATABASE statement (apparently) gets created with a nvarchar(4000) as the definition for the input parameter.
However, I regularly have to flush log parts larger than 4000 chars, so I'd like that to be nvarchar(MAX).
Now I think I can do some jiggery-pokery and use Management Studio to re-define the CREATE DATABASE statment, but I'd actually like to define the fact that I want it to be MAX in the project/solution, so the deployment gets done correctly and I don't have to start adding large wads of comments and/or documentation for anyone who needs to maintain this code after me.
Is there any way to specify this in the code or maybe in the AssemblyInfo or something like that?

Revisiting this years later, I tried to use SqlChars in a function that read data from the database and returned a formatted string with data in it. Using SqlChars actually made the function bomb, stating that it could not find linked server System - an error message that seems to have nothing to do with the problem, as I was never referencing a linked server in the first place.
Changing the return type and parameters back to SqlString, adding [return:SqlFacet(MaxSize = -1)] attribute to the function, and adding [SqlFacet(MaxSize = -1)] to each parameter made my function work properly.

Try using SqlChars. SqlChars automatically maps to NVARCHAR(MAX)

Related

Short Circuit in SMO-created stored procedure

Due to a huge and hateful database that I'm not allowed to rationalise, I am forced to create a C# Datalayer generator for my app. I'm pretty much done, using T4 to generate Model classes and Insight.Database repos but I needed to create my User Defined Table Types and Stored Procedures via Sql Management Objects.
What I'm interested in is, can I use a short-circuit parameter when creating via SMO? What I want to replicate is something like this:
CREATE PROCEDURE [dbo].[cip_GetLicenses]
#fldIndex int = null
AS
SELECT [fldIndex]
,[fldLicenceData]
FROM [dbo].[tblLicences]
WHERE (#fldIndex is NULL OR (fldIndex = #fldIndex))
I can construct the body of the sproc relatively easily with a string builder and some column iteration, but creating a parameter is done separately.
The StoredProcedureParameter Type does actually have a DefaultValue property but it's a string, and sadly setting it to " = null" simply throws exceptions at run time.
Can anyone advise?

twilio twimlresult post to sql server

So, adapting some of the code from the tutorial here:
I have got a twilio app up and running and it correctly posts and inserts calls into my sql server, although I am trying to add additional fields to be inserted and I ran into some issues. In my controller, this is the method i am using:
[HttpPost]
public TwiMLResult Create(
[Bind(Include = "QuestionId,RecordingUrl,Digits,CallSid,From")]
Answer answer)
{
_answersRepository.Create(answer);
var nextQuestion = new
QuestionFinder(_questionsRepository).FindNext(answer.QuestionId);
return TwiML(nextQuestion != null ? new Response(nextQuestion).Build() :
ExitResponse);
}
My question is two parts. First, how can I add more fields to be added to my sql table? I tried adding StartTime, EndTime, Duration after ,From and adding it to the Model, synced my database so I can see the columns on the table but nothing actually get's inserted. I put the data types as string so maybe that was the issue? I could not tell from the twilio documentation what datatype those fields wer.
The second part of the question is can I put custom fields into that Bind(Include) statement? For instance, can I create a variable called Name and then have the TwiMLResult Create send a string Name along with the twilio data with it as well? Of course, I would add it to the model class and thus to the table.
I guess my problem is is that I don't understand what is happening with the TwiMLResult Create method very well. What is happening exactly? This method here is what is actually RECEIVING the data coming from twilio, correct? and the _answersRepository.Create is what writes it to the database? So I should be able to add more fields and have them written to the db just fine I would think. I just am not sure why the StartTime, EndTime, Duration information isn't coming through to this point. Similarly, I am not sure how to add a custom variable, for instance, to pass the person's name to this point and have it written to the db.
I hope this all makes sense and isn't too convoluted to understand. Thank you in advance everyone! I really appreciate the help!
Syd
EDIT: Basically, I determined that those fields do not come through and thus were passing null values. To answer the second part of my question, you can definitely pass any query values and record them (which is what I ended up doing).

"undefined function call" when using function in a DataSet

I have a DataSet in UserAdmin.xsd with many DataTables. Most of the data come directly from stored procedures. However for one of the tables, I would like to add another column which uses a C# function defined in another file.
I put for the expression for that column: Helper.ObtainUserInfo(user_nm, "displayname"); but that gives me an error "undefined function call".
Helper.cs is located under App_Code/Common/ and the namespace is COM.A.B.C. UserAdmin.xsd is located under App_Code/.
How can I access the function ObtainUserInfo()? Is there something like a using keyword that I could use?
You cannot use DataColumn.Expression to call a .NET-Method to obtain a value. You must refer a column in this table or one of the parent/child tables to calculate the value. For more informations on what you can('t) do with Expressions look here: http://msdn.microsoft.com/en-us/library/system.data.datacolumn.expression%28v=VS.100%29.aspx
Instead of using a method or an expression, i would recommend to do this with SQL whenever possible.
if You provide your code, then it would be very helpful to solve your problem, anyway assuming your problem i have solution, i hope it may helped you
You can open the Code File Which Contain ObtainUserInfo() Function, then You can Refer that Class Name, in other File.
For eg : If you hav solution Named WebApplication1, inside that if you have users class, in that users class, ObtainUserinfo() function is defined,
then You Have to Use statement like this,
Using WebApplication1.Users

Type safe binding to an Oracle Stored Procedure in C#?

We are deploying multiple projects in C# with Oracle databases behind. I would like to implement all of the database logic in Oracle stored procedures as this
keeps all of the database logic in the database
makes it easier to maintain when database structures change
allows re-use of the stored procedures more easily across programming languages
I have test code running where I return rows using a SYS_REFCURSOR and I manually do the data bind on the results as SYS_REFCURSOR could be returning anything - i.e. its not type safe
My question is - is there any way I can define correct types in the stored procedure return type and correctly bind to that type safely in my C# code?
e.g. my PL/SQL procedure looks like this - the return part is not type safe - it could be anything. If I wanted to re-use it from another Oracle package then it will not have the correct type checking
PROCEDURE get_risk (p_process_id IN NUMBER, p_risk OUT sys_refcursor);
and my C# code looks something like the following. I have cludged this together from several classes so hopefully it makes sense. When I extract the data from the DB call I am manually defining the data types - I need to know in the C# code what the Oracle data types are
// setup procedure call
_oracleCommand = new OracleCommand("risk_pkg.get_risk", _conn.OracleConnection);
_oracleCommand.Parameters.Add(new OracleParameter("p_process_id", OracleDbType.Int64, processId, ParameterDirection.Input));
_oracleCommand.Parameters.Add(new OracleParameter("p_risk", OracleDbType.RefCursor, null, ParameterDirection.Output));
_oracleDataAdapter = new OracleDataAdapter(_oracleCommand);
_dataSet = new DataSet();
// call Oracle
_oracleDataAdapter.Fill(_dataSet);
// extract data - hand coded binding
Int64 dbRiskId = (Int64)_dataSet.Tables[0].Rows[0][_dataSet.Tables[0].Columns["risk_id"]];
Int64 dbClientId = (Int64)_dataSet.Tables[0].Rows[0][_dataSet.Tables[0].Columns["client_id"]];
return new Risk(dbRiskId, dbClientId);
This isn't necessarily a problem - I just want to know if there is a better way of doing this to make my PL/SQL more obvious in what it is returning, and making my C# code not have to know the Oracle data types - encapsulating me from database structure changes
Accepted solution : this seems to be the practical solution. I'm still slightly unsatisfied that my Oracle procedure isn't defining its return type explicitly, but that life
(You should post a sample of your to test code. Because I'm not sure, if I understand your question correctly.)
The returned type is Object to serve any possible return value. You have to convert it manually. But you could generate the code for the conversions. Define a table or a file with this meta information: which stored procedure returns which types and in which .Net types they shall be converted. Use this meta information to create the C# code.
We fill our RefCursors into a DataTable. The code to assign the table fields to their appropriate member variables is generated out of our meta tables.
I have used T4 text templating to do this with SQL server. Works incredibly well.

How to avoid dependencies between Enum values in code and corresponding values in a database?

I have a number of user permissions that are tested throughout my ASP.NET application. These permission values are referenced in an Enum so that I can conveniently test permissions like so:
btnCreate.Enabled = PermissionManager.TestPermission(Permission.AllowCreate);
However, I also have these permissions stored in the database because I need hold more info about them than just their Id. But this creates a horrible dependency between the enum values and those in the database, an ill considered change to either and I have problems throughout my application. Is there a better way around this issue? Has anyone dealt with this before?
I do not know what the best solution is, I would like to hear that.
Our solution is to explicitly type the enum like
public enum MyEnum : int
{
None =0,
Value = 1,
AnotherValue =2
}
And save the integer value to the database. When for instance the Value 1 is removed, you will still be able to use the enumeration and AnotherValue still has the value 2 in the database.
Or maybe store the enumvalues as string in the DB. ToString();
Using enum values is acceptable to do as long as you never change the already assigned values. If you were using the standard role-based authorization in .NET you would still be relying on the exisistence of certain text strings in the corresponding role table in the database.
We use a small application that generates enum code (example: NorthwindEnums.cs) from the database. We make sure to run it and update affected libraries whenever the database changes.
We also try to keep our enums starting at 0 and sequential to avoid issues with web service references in C#.
A while back I built a little tool to do this for my company that would use attributes on the enum fields to allow "synchronisation" with the table in the database.
The tool could scan an assembly and generate appropriate INSERT/UPDATE SQL commands that would sync the database with the enum definition in the code.
I add an extended property on any table that I will need to access in code as an enum. I then use code generation software (codesmith, T4, whatever) to generate all my enum's for me by looking up any table with this property. Any table that is to be used for this abides by some basic rules (must have a Name column, etc.) so the code generator knows which column to use as the name for the enum's elements.
Once values are added to those tables we take care to virtually never change them to avoid breaking the build.

Categories