I have several stored procedures in my database. For example a delete stored procedure like:
alter procedure [dbo].[DeleteFactor]
#Id uniqueidentifier
as
begin
delete from Factors where Id = #Id
end
When I call this from code like this:
dc.ExecuteSprocAccessor("DeleteFactor", id);
then the row does not get deleted. However this code functions:
dc.ExecuteNonQuery("DeleteFactor", id);
id is a passed in parameter and of type Guid.
Can anyone explain why the second does work and the first approach does not? I find it quite strange as the first method is clearly to be used with stored procedures.
According to Retrieving Data as Objects, the ExecuteSprocAccessor method uses deferred execution (ala LINQ). So, in the first approach, since you are not accessing the results of the DeleteFactor stored procedure the SQL call is not being made.
I would use the second method anyway since you really are executing a non-query. Also, the first approach may lead to some confusion since the ExecuteSprocAccessor is designed to retrieve data. e.g. "Is data supposed to be returned here? Maybe something was missed?"
Just call ToArray or ToList on the result of your ExecuteSprocAccessor to make it execute.
Related
I have a stored procedure in my project under sql/my_prod.sql
there I have my function delete_entity
In my entity
#NamedNativeQuery(name = "delete_entity_prod",
query = "{call /sql/delete_entity(:lineId)}",
and I call it
Query query = entityManager.createNamedQuery("delete_entity_prod")
setParameter("lineId",lineId);
I followed this example: http://objectopia.com/2009/06/26/calling-stored-procedures-in-jpa/
but it does not execute the delete and it does not send any error.
I haven't found clear information about this, am I missing something? Maybe I need to load the my_prod.sql first? But how?
JPA 2.1 standardized stored procedure support if you are able to use it, with examples here http://en.wikibooks.org/wiki/Java_Persistence/Advanced_Topics#Stored_Procedures
This is actually they way you create a query.
Query query = entityManager.createNamedQuery("delete_entity_prod")
setParameter("lineId",lineId);
To call it you must execute:
query.executeUpdate();
Of course, the DB must already contain the procedure. So if you have it defined in your SQL file, have a look at Executing SQL Statements from a Text File(this is for MySQL but other database systems use a similar approach to execute scripts)
There is no error shown because query is not executed at any point - just instance of Query is created. Query can be executed by calling executeUpdate:
query.executeUpdate();
Then next problem will arise: Writing some stored procedures to file is not enough - procedures live in database, not in files. So next thing to do is to check that there is correct script to create stored procedure in hands (maybe that is currently content of sql/my_prod.sql) and then use that to create procedure via database client.
All JPA implementations do not support calling stored procedures, but I assume Hibernate is used under the hood, because that is also used in linked tutorial.
It can be the case that current
{call /sql/delete_entity(:lineId)}
is right syntax for calling stored procedure in your database. It looks rather suspicious because of /sql/. If it turns out that this is incorrect syntax, then:
Consult manual for correct syntax
Test via client
Use that as a value of query attribute in NamedNativeQuery annotation.
All that with combination MySQL+Hibernate is explained for example here.
I have a process in my program that uses an Entity Framework 4 EDM. The entity context object contains function imports for calling stored procedures.
The process receives a batch of data from a remote server. The batch can consist of data for any of our tables / data types (each data type is stored in its own table). The batch can also contain data for the same row multiple times. It has to handle this as a single insert (for the first occurance) and one or more updates (for each subsequent occurance). The stored procedures therefore implement an upsert operation using the INSERT ... ON EXISTING UPDATE command.
Our code basically determines which stored procedure to call and then calls it using the entity context object's method for that stored procedure. Then entire batch has to be done in a single transaction, so we call context.Connection.BeginTransaction() at the beginning of the batch.
There is one data type that has millions of rows. We need to load that data as quickly as possible. I'm implementing logic to import that data type using the SABulkCopy class. This also needs to be a part of the single transaction already started. The issue is that I need to pass an SATransaction to the SABulkCopy class's constructor (there is no way to set it it using properties) and I don't have an SATransaction. context.Connection.BeginTransaction() returns a DBTransaction. I tried to cast this into an SATransaction without success.
What's the right way to get the SABulkCopy object to join the transaction?
We gave up on the SABulkCopy class. It turns out that it doesn't do a bulk load. It creates an SACommand object that executes an INSERT statement and inserts the rows one at a time. And it does it inefficiently, to boot.
I still needed to get at the SATransaction associated with the DBTransaction returned by context.Connection.BeginTransaction(). I was given some reflection code that does this in response to another question I posted about this:
SATransaction saTransaction = (SATransaction) dbTransaction.GetType()
.InvokeMember( "StoreTransaction",
BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.InvokeMethod |
BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.NonPublic,
null, dbTransaction, new object[ 0 ] );
The program does what it needs to do. It's unfortunate, though, that Microsoft didn't make the StoreTransaction property of the EntityTransaction class public.
I need to change the value of a property when I query the database using EF4. I have a company code that gets returned and I need to translate it to another company code, if needed. So, there is a stored procedure that is used to do this currently. Here's the old select statement.
SELECT companyName, TranslateCompanyCode(companyCode) as newCompanyCode FROM companyTable where companyCode = 'AA';
TranslateCompanyCode is the stored proc that does the translation. I'd like to do this in my new code when needed. I think I might need to use a Model-Defined Function. Anyone know how I can do this?
For your scenario, I would use a JOIN. Model-defined functions are cool when you need to perform a quick function on a value (particularly without an additional query). From a performance standpoint, a JOIN will be faster and more efficient than trying to put the sub-query in a model-defined function - particularly if you are selecting more than 1 row at a time.
However, if you do still want to use Model defined functions, then this example should point you in the right direction as to how to run a query within the function. This implementation will also be more complex than just using a join but is an alternative.
I have a bunch of dimension tables that have unique ID and Name fields. I need a T-SQL function that returns an ID when passed a table name and a value for the name field.
I'm guessing the function would build a little query then execute it? Performance isn't an issue since this is a one time ETL thing.
Sounds like you want a scalar user defined function
There's a lot of other ways to do it though, and udf's certainly can have some perfomance issues.
I have a temporary table (or, say, a function which returns a table of values).
I want to execute some statements for each record in the table.
Can this be done without using cursors?
I'm not opposed to cursors, but would like a more elegant syntax\way of doing it.
Something like this randomly made-up syntax:
for (select A,B from #temp) exec DoSomething A,B
I'm using Sql Server 2005.
I dont think what you want to to is that easy.
What i have found is that you can create a scalar function taking the arguments A and B and then from within the function execute an Extended Stored Procedure. This might achieve what you want to do, but it seems that this might make the code even more complex.
I think for readibility and maintainability, you should stick to the CURSOR implementation.
I would look into changing the stored proc so that it can work against a set of data rather than a single row input.
Would CROSS/OUTER APPLY do what you want if you need RBAR processing.
It's elegant, but depends on what processing you need to do