Generic wrapper for stored procedure execution - c#

How can I execute stored procedures generically? I tried:
_context.Set<TEntity>();
I want to avoid embedded SQL such as:
context.Database.SqlQuery<TEntity>(storedProcedureName);
However, because the stored procedure is accessed via a Function rather than a Type this does not work. I also tried creating/accessing via a function mapping. The complex type for the return result exists, but this can't be used to obtain the result itself.
Do I need Delegates or is there support for this somewhere?
To be clear, I hope to create something like....
public IEnumerable<TEntityResult> ReadSpAll<TEntity,TEntityResult>(IEnumerable<SqlParameter> sqlParameters)
where TEntity is the stored proc and TEntityResult is the complex return type

See "Using Import Functions to Map Stored Procedures"
# http://msdn.microsoft.com/en-us/data/gg699321.aspx
for code like
var context = new AWEntities();
ObjectResult<OrderDetail> orderDetailEnumerable = context.GetDetailsForOrder(71796);
List<OrderDetail> details = orderDetailEnumerable.ToList();

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?

Argument Exception when passing parameters to a stored procedure (.net sdk)

I have created this stored procedure in a collection in my DocumentDb Account.
https://github.com/Azure/azure-documentdb-js-server/blob/a7a2db8c4abc6ce61d40e08b66358f03fd89f896/samples/stored-procedures/update.js
I am having trouble executing this with the .NET SDK, here is my code.
dynamic[] procParams = new dynamic[] { "myid", "{ $set: { status : 'Draft' } }" };
return await _client.ExecuteStoredProcedureAsync<Listing>(UriFactory.CreateStoredProcedureUri("dbName", "collection", "update"), procParams);
The SDK throws an ArgumentException:
"Cannot Serialize object if it is not document or attachment"
Seems like I can only pass Document's or Attachments which doesn't seem right?
I came across this blog post and it looks like this guy is doing the same but with no issues.
So how do I pass basic parameters to a stored procedure such as strings?
To clarify - it looks like that the exception above refers to an issue with de-serializing the stored procedure's response in to the Listing class (as opposed to referring to serializing the input parameter before executing the stored procedure).
You can verify whether this is true by examining the response of the stored procedure as a string:
var sprocResponse = client.ExecuteStoredProcedureAsync<string>(UriFactory.CreateStoredProcedureUri("dbName", "collection", "update"), procParams).Result.Response.ToString();
If you are able to retrieve the updated document response as a string; than that means the stored procedure successfully executed and should confirm the issue lies with de-serializing the stored procedure response in to the Listing class.
A common mistake here is for POCOs to extend the Document class (as opposed to the Resource class: Microsoft.Azure.Documents.Resource). Please make sure Listing does not extend Document, and that the response from the stored procedure can be de-serialized to the Listing class.

WF 4.5: Is it possible to add variables dynamically at runtime?

We are writing a custom activity. In this activity it is possible to set a database connection string and a name for a stored procedure. At runtime the stored procedure is executing. Now we have some stored procedures which has input parameters.
Is it possible to generate variables dynamically in WF 4.5 for each input parameter in the stored procedure? Reading the parameters from the stored procedure is not the problem, but I dont have any idea how to generate the variables.
Example:
The user enters a name for the stored procedure to be executed (2 input params #Variable1 and #Variable2). Now in the variables tab should be 2 variables: #Variable1 and #Variable2. If the user changes the name in the stored procedure then in the variables tab should be the new params (for example only #Variable2)...
We spent a lot of time on this issue. But the only thing we have learned is that the activity has to be a NativeActivity and the variables should be added in the CacheMetadata method. But if I add a variable with AddVariable() method nothing happens :(
If you are open to including third-party libraries, you could try using an ORM tool like Dapper to accomplish this. A Dapper query generally takes an anonymous type to supply its parameters. Typical code for creating a custom object from fields in a database would look something like this:
IDbConnection db = New IDbConnection(...);
int id = 527; // normally passed in - using a hard coded value would defeat the purpose...
string myQuery = "SELECT Engine, Transmission, Make, Model, BodyStyle FROM Table WHERE ID = #ID";
Car result = db.Query<Car>(myQuery, new { ID = id }).First();
So I believe that you could use reflection to pass in the type ("Car") using reflection and create an anonymous object or pass in an actual object with an "ID" property at runtime. It will automatically create a custom Car object with the resulting data, assuming that the Car object has properties of Engine, Transmission, Make, Model, BodyStyle, etc.
Note that if you don't supply the type you expect to get back, you get an ExpandoObject: Creating an anonymous type dynamically? - you may also be able to pass one of these in for your input parameters, which would mean that you could create it at runtime.
This guy came up with a generic method for Dapper that may help you: http://www.bradoncode.com/blog/2012/12/creating-data-repository-using-dapper.html
What he came up with is something like this:
IEnumerable<T> items = null;
// extract the dynamic sql query and parameters from predicate
QueryResult result = DynamicQuery.GetDynamicQuery(_tableName, predicate);
using (IDbConnection cn = Connection)
{
cn.Open();
items = cn.Query<T>(result.Sql, (object)result.Param);
}
return items;

Function import that returns object instead of complex type

I'm building dynamic table with stored procedure, so when adding function import, I want it to return object instead of specific type. Is it possible? Thanks
UDPATE
I've tested this and it doesn't work - the call to SqlQuery returns a System.Object. I'll not mark for deletion as it is useful to know that this technique doesn't work.
it should be possible but as #BorisB has said, I'm not sure why you would want to ...
List<dynamic> result = context
.Database
.SqlQuery<dynamic>("select * from ......")
.ToList();
If it were possible what would be the type of that returned object and how would you access its properties?
You'd somehow had to build an EF complex type and a function import at runtime or build a model using ModelBuilder (but you still don't have a data class), which may be possible in theory but it in practice it is way above the problem you are solving.
Maybe it would be better to use ADO.Net directly or modify those SPs to return results as XML which is then consumed by the client (but in XML case you still don't have compiled type of returned objects, so no deserialization, only XPath).

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.

Categories