Reading entities intended sql query? - c#

I have a system where the customer wants to rework the current model so that everytime a user makes a change an administrator must accept the change before its written to the database..
I was thinking of doing a quick fix for this by overriden SaveChanges and taking each object in the ObjectStateManager and adding its intended sql code to a limbo table that would keep the inteded sql query saved until an admin has accepted it (and then run it).
I know that you can use ToTraceString() on database querys, but can you somehow pull the intended sql query on the object taken from ObjectStateManager?
Was thinking something like this:
var modified = DB.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Modified);
foreach (var mod in modified)
{
//Insert the query to the limbo table
tblPendingChanges change = new tblPendingChanges();
//Code omitted
change.sql = mod.Query;
//Code omitted
DB.tblPendingChanges.AddObject(change);
mod.Delete();
}
DB.SaveChanges();

Your solution is terrible. If you have the requirement that each change must be approved it leads to approval workflow where you save changes to some temporary store and move them to the main tables once approved. It is really not done on SQL level. If you need something working on SQL level don't use high level tools like Entity framework because they are really not designed to support this. For example EF will not provide you SQL commands generated for data modifications.

I solved this issue by using a entity wrapper found here
This allowed me to read each sql statement before it was sent to the server. Redirecting it.
I had to edit the wrapper to allow parameters to be inserted correctly into the statement so that the sql statement could be run.

Related

Check if the snapshot already Exist in SQL server using C#

I want to check in a database that if it snapshot is already existing. If yes I want to delete the snapshot and create a new one. How can i do it in an efficient manner. Also is it possible to check the time when it was created? I am using C# at back-end to achieve it.
You could use a SQL query to determine whether a database is a snapshot and then execute that query from with C#.
This SQL query should help you determine if a database snapshot exists:
select *
from sys.databases
where name = '<your_db>'
and source_database_id is not null
I would refer to this article for an example of how to execute SQL from within C#: https://msdn.microsoft.com/en-us/library/dw70f090(v=vs.110).aspx#_SqlClient
The code will likely need elevated privileges within SQL Server in order to execute this query so be careful with how these features are exposed. I strongly suggest using a parameter-based query as shown in the example within that link to avoid exposure to a SQL injection attack.
See this question for more information on how to determine if a database is a snapshot using SQL server: https://dba.stackexchange.com/questions/35105/how-can-i-query-for-existing-database-snapshots-in-sql-server
This article contains information on dropping snapshots from within SQL server: https://msdn.microsoft.com/en-us/library/ms190220.aspx
Similarly, this article indicates how to create one: https://msdn.microsoft.com/en-us/library/ms175876.aspx
Please be careful when dropping snapshots via code. The same permissions used to drop a snapshot allow the user to drop a database.
This article indicates that the date the snapshot was created is stored in the column create_date: https://msdn.microsoft.com/en-us/library/ms178534.aspx
If it were me, I'd look at the Database class in the SMO library. Specifically, the IsDatabseSnapshot and DatabaseSnapshotBaseName properties. If memory serves, CreateDate should reflect the creation date of the snapshot, not the source database.

How can I prevent users running UPDATE statements via a query builder

We are building a reporting framework into our application, which necessitates the use of a query builder. Ultimately, we want power users to be able to build SELECT queries to be used to populate the report dataset.
Datasets are built using a DataAdapter (either MSSQL or SQLite). Are there any tools we can use to ensure that the queries built by the end user can only be SELECT statements?
EDIT:
As mentioned above, we target SQLite as one of our supported backends No DB permissions can be set on this platform.
Set right permissions to DB. It's the best solution.
EDIT:
For SQLLite you can set read only permissions for file - in the file system.
Give the user that you execute the SQL as only the db_datareader permission to ensure that they cannot do anything but read the data.
This question gives more info on how to do that:
How to give a user only select permission on a database
If the query builder is done in house, and if your query builder returns a the SQL statement in a string, you can parse it either looking for Update statements keyworks or with Regex, if you want to spare the users the trouble of creating an update query then realizing that they can't run it, then you should consider doing this check continiously as they create the query. Alternatively, you can use a third party query builder, like this one: http://www.activequerybuilder.com/, unfortunately i belive it doesn't support anything else but Select statements but it may be worth the shot.
I think all you have to do is wrap the QueryBuilder and expose only permited operations.
I is not good to do thinks the other way around, like letting the user construct a query and at the end you tell him it is not permissable.

How to capture and record the activity of a SQL table

We have a winform app, all the SQL is inline and no stored procedure is used unfortunately.
What is the best way to keep a trail of what action (INSERT, UPDATE or DELETE) is performed against a SQL table, monitor and capture a record of the activity going on in a single table.
I know SQL server profiler is available but ideally I don't want to keep the profiler running all the time, what I need is something running behind the scenes and capturing all the activity for one table.
I thought of using triggers but there are some disadvantages of using it so I was wondering if there are other options?
Thanks
If you're using SQL Server 2008 (and up), Change Data Capture sounds like a good place to start:
http://msdn.microsoft.com/en-us/library/bb522489(v=sql.105).aspx
If you are using ORACLE, you can audit a table using this statement (if fireid
is the name of the user doing the updates):
AUDIT SELECT TABLE, UPDATE TABLE, INSERT TABLE, DELETE TABLE BY fireid BY ACCESS;
The results will be stored in the SYS.AUD$ table
(If you're using another database just search the documentation for auditing DML statements.)
SQL SERVER: There is a feature called "SQL AUDIT" Is this what you're looking for?
http://www.bradmcgehee.com/2010/03/an-introduction-to-sql-server-2008-audit/
There are several ways. If you just want to do it in Code (depending on your program)
You can just add the commands to a list and write them to a file.
If you are using EntityFrameWork then I would log the data changes. And use of stored procs is really best when using EF.
A sample of your code or project would help. TransactionLogs already capture that information.
And OBVIOUSLY your using Sql Server THOSE ORACLE PEOPLE ARE JUST SO JEALOUS.
Also look at using DataSourceViews, it's a way to tell what is going on with the server.
I think SQL Server CHANGE TRACKING TeEchinique is best suitable for your requirements.

ADO.net update without SQL?

This might be a dumb question. But does ADO.net support updating to a database without having to write SQL commands?
Example:
I have a method that reads from database and keeps the rows in memory. I then modify some of the rows. Is it then possible to make ADO.net update the newest changes to the database without having to write an update SQL statements but instead let ADO.net figure it out?
I am asking this because I might want to update at a much later point. I could just store the SQL statements in a list but then I would be doing many updates instead of just one big one which would take longer time.
What you need is some sort of ORM, and ADO is not an ORM. So, no. You must write the SQL. You could maybe simplify things by writing a stored procedure, though. Then you can use ADO parameters
If you want, you can save your changes as objects in memory until you need to actually persist them. Then you can have a mapper that will take the object and write the SQL for you. However, then you are redoing some of the work of what is already done in an ORM
Like the sql you used to get the data, you need sql to put the data. It also needs to update what column to update. I don't think it can be automatic. Or use the Entity Framework. Probably saving the objects to be updates (IDs) is the way to go or update instantly.
ADO.NET supports DataAdapters and DataSets which allow you to do the following:
Manipulate data within your DataSet.
Push changes to the database by passing your DataSet as a parameter to the Update method of the DataAdapter.
In order to get the DataAdapter to push the changes it is necessary to specify insert, update, and delete commands. You will have to specify some sql in your command configuration but it is like a template of the sql statement that will update each row that you operate upon rather than your having to manually track changes.
Once you have configured your commands, use the UPDATE method with the DataSet as the parameter and it will persist your changes based on your commands. You will not need to track the individual sql changes.
A sample of configuring commands can be found here.
A sample of calling the update can be found here.

Entity framework - Reducing round trips to the database

I'm writing an app using WPF, Entity framework and SQLServer, all very run of the mill stuff. I was having a look at what calls get made to the database using sql profiler and found quite a few unnecessary calls. The first one was solved pretty easy but I have included it for anyone reading this thread in the future. Assuming I have a table structure with 3 tables like this Invoice->InvoiceDetail->Product
1) When I load up an Invoice object, it will then execute a seperate statement to retrieve each InvoiceDetail item. This is solved pretty easy by using the Include statement, eg
context.Invoices.Include("InvoiceDetails").Where(i => i.Something == somethingelse);
2) When I delete an Invoice the database has a cascade delete which automatically deletes all of the InvoiceDetails. However EF still insists on calling a delete for each of the InvoiceDetail objects that it has in memory. If an invoice has 100 items on it then it will execute 101 statements instead of 1. This is bad.
3) In addition to the extra statements executed in point 2, assuming each InvoiceDetail object points to a product and I have caused the products to loaded into memory (this would happen if I showed the invoice before I deleted it) then EF executes a useless update statement on every product!!!! In fact this update statement is more than useless because if someone else has changed something about the product in the mean time then this code will change the data back!! If I'm logging changes then we get useless log entries. I suspect it is doing this because Product would have had an InvoiceDetails collection which has had some items removed, but the Product itself has not changed so why the update?
Thanks for reading
Cheers,
Michael
The initial behavior was something known as lazy loading. You have replaced it with eager loading which is exact solution for this problem.
For entity framework this is the only correct behavior because EF doesn't support any batch modifications. Every record must be deleted with its own statement and round trip to the database. Once you load entities to memory you simply have to delete them one by one otherwise you will get exception before any database call will be done (= database cascade delete will not help you). The only workaround is custom stored procedure for deletion and disposing the current context after running the stored procedure because its internal state will not be consistent with the database.
This is interesting. It would require little bit more investigation but it can be simply design flaw / bug in EF and you will most probably not avoid it (unless you use stored procedure as described in 2.). If you want to avoid overwriting changes in Product you must involve optimistic concurrency. In such case your changes will not be overwritten but your delete will fail with OptimisticConcurrencyException. I will check this behavior later and let you know if I'm able to reproduce it and find any workaround.
I've been using this as a solution to let SQL Server handle the cascading deletes without the EF hit.
Public Sub DeleteCheckedOutByUser(ByVal username As String)
Dim cmd As String = String.Format("delete Maintenance.CheckoutManager where CheckOutTo = '{0}'", username)
_context.ExecuteStoreCommand(cmd)
End Sub
Sorry it's in VB, that's what my current client is using. If you have any trouble translating what I'm saying just let me know.
To remove the cascading deletes (and presumably rely on SQL Server to do the deletes), see the approach here: http://geekswithblogs.net/danemorgridge/archive/2010/12/17/ef4-cpt5-code-first-remove-cascading-deletes.aspx

Categories