I've started using Enterprise Library and have the following questions:
1)How do I add output parameter to this query and how do I get it back:
public int InsertDoc(HDocument document)
{
Database db = DatabaseFactory.CreateDatabase();
int result;
var reader = db.ExecuteNonQuery("sp_InsertDocument",
document.AddedDate,document.AddedBy, document.Title))
.
.
.
}
The db.AddOutParameter requires paremetrers that I don't have like DbCommand.
2)I have a few methods that work with database (I transfer from ADO.net) stored procedures,
do I have to declare : Database db = DatabaseFactory.CreateDatabase(); in each one of them or I can reuse it?
1) - You can make a DbCommand thusly:
DbCommand dbCommand = db.GetSqlStringCommand("sp_InsertDocument");
and retrieve the output parameter after execution with:
db.GetParameterValue(dbCommand, "outputParameterName");
Here's a good example of using EntLib to execute a sproc with output params:
http://www.devx.com/dotnet/Article/30910/0/page/4
2) - You can use DatabaseFactory.CreateDatabase() in each method, that's fine. EntLib will manage the connections as necessary.
As an aside, if you're only using the db variable once in a method, then you could simplify your code slightly by using an inline temp instead of declaring a variable, i.e.:
var reader = DatabaseFactory.CreateDatabase().ExecuteNonQuery(....
Related
I am using EF to call stored procedures like this:
db.Database.ExecuteSqlCommand(sql, parameters);
These procedures do multiple inserts and updates. I added, a TRY region and a COMMIT at the end of the TRY and a ROLLBACK (inside a CATCH) logic but this is giving me an error which I traced back to this:
Stackoverflow Explanation
If the case is that EF wraps the stored procedure calls then does this mean there is no reason to do that inside the stored procedure or should I leave the COMMIT and ROLLBACK in the SP and do this:
db.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, sql, parameters);
If possible, you should not handle the transaction in the stored procedures and go for something like this, with DbContexts relying on existing connection and transaction :
using (var conn = new SqlConnection("YourConnectionString"))
{
conn.Open();
using (var tran = conn.BeginTransaction())
{
using (var ctx1 = new DbContext(conn, false))
{
ctx1.Database.UseTransaction(tran);
ctx1.Database.ExecuteSqlCommand("Exec YourStoredProc1");
ctx1.Database.ExecuteSqlCommand("Exec YourStoredProc2");
}
using (var ctx2 = new DbContext(conn, false))
{
ctx2.Database.UseTransaction(tran);
ctx2.Database.ExecuteSqlCommand("Exec YourStoredProc3");
}
tran.Commit();
}
}
As the transaction is already provided, Entity Framework will not wrap yur calls in new transactions.
You can handle the rollback logic for errors with try{}catch(){}, of course, but also with any business code you want.
You can do like this:
using (TransactionScope scope = new TransactionScope())
{
//EF context
using (TestDatabaseEntities contect = new TestDatabaseEntities())
{
//TODO:`enter code here`
}
}
The rollback will rollback all opening (active) transaction. Incase using EF, EF always auto create an root (outermost) transaction, so that the rollback inside a stored proc will rollback the transaction created by EF as well and it will cause error.
There is a way to get over, using Save point -> seee https://msdn.microsoft.com/en-us/library/ms188378.aspx
I've applied the template save point for EF and it works well.
I'm newbie in SQLite.
I would like to query my SQLite database to get multiple rows.
When I add a new item in my local database I call this method Add:
public bool Add<T>(string key, T value)
{
return this.Insert(new SQliteCacheTable(key, this.GetBytes(value))) == 1;
}
_simpleCache.Add("favorite_1", data1);
_simpleCache.Add("favorite_2", data2);
_simpleCache.Add("favorite_3", data2);
Then,
I would like to retrieve from local database all entries where key starts with "favorite_"
to returns all objects in the database which are "favorite" objects.
I'm experienced in Linq, and I would like to do something like this:
IEnumerable<Element> = repository.Find((element) => element.Key.StartWith("favorite_"))
In the SQLiteConnection class there is a method like this:
SQLite.Net.SQLiteConnection.Find<T>(System.Linq.Expressions.Expression<System.Func<T,bool>>)
But I would like the same with in returns a collection IEnumerable<T>.
Can you help me please?
Thank you.
Jool
You have to build your query on the table itself, not the connection:
Assuming:
SQLiteConnection repository;
Then the code would look like:
var favorites = repository.Table<SQliteCacheTable>().Where(item => item.StartsWith("favorite_"));
The favorites variable is of type TableQuery<SQliteCacheTable> though, so it does not yet contain your data. The execution of the actual SQL query will be deferred until you try to access the results (by enumerating with foreach or converting to a list with ToList, for example).
To actually observe what's going on on the database, you can turn on tracing in sqlite-net, by setting repository.Trace = true on your SQLiteConnection object.
Finally, it's worth mentioning that you can also use the C# query syntax on TableQuery<T> objects, if your comfortable with it. So your query could become:
var favorites = from item in repository.Table<SQliteCacheTable>()
where item.StartsWith("favorite_")
select item;
this is a method i was reading about #MSDN ,
my question is if for an example i would like to use it on a stored procedure
with the fact that the query of that stored procedure is already specifying columns to select from the table like following :
SELECT Columnsome, columnother, , , , ...FROM thisSQLdbTable
though i would like to implement the approach of that specific method , it seems very advanced from a little research i have made on
"the best way" available to extract data from SQL Server into Asp.net DataTable.
public static DataTable GetCustomerData(string dataSetName,
string connectionString)
{
DataTable table = new DataTable(dataSetName);
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlDataAdapter adapter = new SqlDataAdapter(
"SELECT CustomerID, CompanyName, ContactName FROM dbo.Customers", connection);
DataTableMapping mapping = adapter.TableMappings.Add("Table", "Customers");
mapping.ColumnMappings.Add("CompanyName", "Name");
mapping.ColumnMappings.Add("ContactName", "Contact");
connection.Open();
adapter.FillSchema(table, SchemaType.Mapped);
adapter.Fill(table);
return table;
}
}
or is it not the method to use if i am querying via SP that specifies the selected column
i could actually drop that stored procedure if it is not requiered to select /specify columns
the stored procedure is doing a specific calculation and updates the table with results of calculation then i am switching it's "MODE" to select results from the table that was updated.
what i did is recyceling (; giving it a parameter (bit type)
stored procedure then asks for the value of supplied bool / bit Parameter,
if its is status true it updates (doing its original task it was made for)
if its false its doing a select oporation so i am using it as i would with 2 separated commands
but now that i have search for a better way to extract data from db into a Data table
i give up on the two way SP and i will make a selection via the exaple above if they're not intended to be used thogether as with my current SP that does preselection when servs the GetCustomersData() above.
So the question is do i need to let the function to make the selection or can i serve it with my sp ready made selection to implemet it with GetCustomersData() in the way that it will only do rest of task and only mapp the columns that was preselected
Still a bit confused on your actual requirement but here goes:
I See you are using a direct query in your C# code, 'best way' would be to make a SP out of it then say:
SqlCommand command = conn.CreateCommand();
SqlDataAdapter sqlAdapter = new SqlDataAdapter(command);
command.CommandType = System.Data.CommandType.StoredProcedure;
command.CommandText = "sp_GetCustomerData";
Then after you have added parameters if needed do:
conn.Open();
sqlAdapter.Fill(dtResult);
conn.Close();
Where dtResult is Datatable.
So you do not need to do any mapping in this case, and since you are using a SP from the Database it will work faster than your direct query and you can change the query logic any time without the need of re deploying your code.
Stored procedures are perfectly valid in this use case. however, if you want more of a properly mapped table, you have several options, some of which go beyond the use of DataTables.
You can use strongly typed DataSets or perhaps use an ORM (object relational mapper).
ref: Typed Datasets: http://msdn.microsoft.com/en-us/library/esbykkzb(v=vs.71).aspx
ref: What is an ORM : http://en.wikipedia.org/wiki/Object-relational_mapping
EXAMPLES OF ORM'S
ref: Entity Framework : http://msdn.microsoft.com/en-us/data/ef.aspx
ref: NHibernate: http://nhforge.org/
I've been building this project as the solo dev for a while, and while I'm comfortable in the front end and middle tier, I don't really think I'm doing the database the way I should be, and the reason why is because I simply don't really know of any other way. The way I'm currently getting data is by testing out queries in my MySQL workbench and copying and pasting the SQL as a string literal into a method that makes a call to the DB, pulls the data and hydrates my objects.
This hasn't really been a problem until recently, when I had to create a monster of a query and it got me thinking that maybe there's a better way to do this. I don't have a formal DAL separated out, so I know there's room for improvement there, but I was curious about what the correct way would be to store SQL strings. I assume there is a tool somewhere built into VS10 where I can manipulate and work with SQL as SQL instead of as a string.
You should be doing this in stored procedures. That will basically format and store your query. You set parameters that are passed in from your code, then read out the results.
Example:
The C# method:
private void SetNote()
{
const string sql = "sp_SelectControllerNoteByID";
using (var conn = MocSystem.GetMocDbConnection())
{
using (var comm = new SqlCommand(sql, conn))
{
comm.CommandType = CommandType.StoredProcedure;
comm.Parameters.Add(new SqlParameter("#ControllerNoteID", ControllerNoteId));
try
{
conn.Open();
using (var rdr = comm.ExecuteReader())
{
while (rdr.Read())
{
CommentText = rdr["NoteText"].ToString();
_commentor = new User(new Guid(rdr["NoteAuthor"].ToString()));
CommentDate = (DateTime)rdr["NoteDate"];
MocRequestId = (int)rdr["MocRequestID"];
}
}
}
catch (Exception ex)
{
HasError = true;
ErrorMessage += "\nThere was a problem building the note: " + ex.Message;
}
}
}
}
The stored procedure on the DBMS (sql server in this example):
ALTER proc [dbo].[sp_SelectControllerNoteByID]
#ControllerNoteID int
AS
SELECT
ControllerNoteID,
NoteText,
NoteDate,
NoteAuthor,
MocRequestID
FROM
ControllerNotes
WHERE
ControllerNoteID = #ControllerNoteID
So here we call the stored procedure which in this case is just a simple select statement, then we read it out into an object via ADO. Now, this way, you can modify your query without recompiling. Unless you add parameters, in which case you'll have to update those in your code as well.
I'm developing an application in AIR via Flex, but I'm not seeing where I'm going wrong with SQLite (I'm used to MySQL). Parameters work, but only in certain instances. Is this part of the built-in sanitation system against sql injection? Thanks for any help!
Works:
sqlite
"INSERT :Fields FROM Category", where the parameter is :Fields = "*"
as3
var statement:SQLStatement = new SQLStatement();
statement.connection = connection;
statement.text = "INSERT :Fields FROM Category";
statement.parameters[":Fields"] = "*";
statement.execute;
Doesn't Work (SQL syntax error at ":Table"):
sqlite
"INSERT :Fields FROM :Table", where the parameters are :Fields = "*" and :Table = "Category"
as3
var statement:SQLStatement = new SQLStatement();
statement.connection = connection;
statement.text = "INSERT :Fields FROM :Table";
statement.parameters[":Fields"] = "*";
statement.parameters[":Table"] = "Category";
statement.execute;
Generally one cannot use SQL parameters/placeholders for database identifiers (tables, columns, views, schemas, etc.) or database functions (e.g., CURRENT_DATE), but instead only for binding literal values.
With server-side support for parameterized (a.k.a. prepared) statements, the DB engine parses your query once, remembering out the peculiars of any parameters -- their types, max lengths, precisions, etc. -- that you will bind in subsequent executions of the already-parsed query. But the query cannot be properly parsed into its syntactic elements if critical bits, like database objects, are unknown.
So, one generally has to substitute table names oneself, in a stored procedure or in client code which dynamically concats/interpolates/whatevers the SQL statement to be properly executed. In any case, please remember to use your SQL API's function for quoting database identifiers, since the API won't do it for you.
Not sure if this is the same but I ran across something similar in Java. Basically you can't add a table as a parameter so you must generate the statement like so:
var statement:SQLStatement = new SQLStatement();
statement.connection = connection;
statement.text = stringUtil.substitute("INSERT :Fields FROM {0}", "Category");
statement.parameters[":Fields"] = "*";
statement.execute;
This is mostly likely not the securest solution, so you might want to some custom validation of the data before you add the table name.. so someone doesn't try to send it the table name ";drop tableName..."