executing insert\update\deletes - Use Linq? - sql-server

I was looking at using linq to sql (or EF) rather than in line\dynamic sql within my application but have hit a possible issue. My application modifies data against any number of random databases accross several sql instances, linq appears to structured towards a single database scenario. Would it be best to just continue using in line sql or is there a method of using linq without tying it down to a single database?
An example of what I'm doing at the moment:
Using cn As SqlConnection = (ConnectionString)
Using cm As SqlCommand = New SqlCommand("< Dynamic sql>;", cn)
cn.Open()
cn.ChangeDatabase(Database)
cm.ExecuteNonQuery()
End Using
End Using
And example of a query would be:
DELETE FROM settings WHERE [Sec] = 'ON' AND [Key] = 'last'; INSERT Settings([Sec], [Key], [Val]) values('ON', 'last', GETDATE());
Although I am executing stored procedures within these databases, some custom, others for adding users (sp_adduser)
All target databases have the same structure, so any query\linq would work against it.

With LINQ, you are correct in that a DataContext goes to one single database, but you can have many DataContexts, each going to a different database. You can have, for example, a SettingsDataContext going to the database with your settings and a UsersDataContext going to the database with your users, or however you have it set up.
There is the syntax of it all. Here is a link to some examples of doing inserts and selects with ADO.NET and Linq to SQL.
http://blogs.msdn.com/b/wriju/archive/2008/07/14/linq-to-sql-vs-ado-net-a-comparison.aspx
One thing I have heard often is that Linq to SQL is for those that aren't real comfortable with SQL or who just like to work in the realms of C# or VB.NET code more than having to switch thought patterns and think in the ADO.NET/inline SQL realm.

Related

How to log custom metadata/context info with each query

I'm making extensive use of Entity Framework, and I need to optimize a lot of DB work.
I see many inefficient queries running in sys.dm_exec_sessions etc, but the problem is I don't have much context as to which code is initiating this query.
is there a way in EF to add some 'context' to each query, which can be viewed in the sys.dm_ queries?
pseudo-code:
dim d=mydbcontext
d.ContextInfo="Report Window 99"'???
dim results=d.set(of client).ToList
And then when I view SQL Servers log, I'll see next to each query the 'ContextInfo' that I set.
I see that SQL Server has a field context_info, but I haven't manage to see it in sys.dm_exec_sessions, also I have no idea how to set it via EF (and its limited to numeric values)
Thanks so much!
heres a very simple way
Dim csb = New SqlConnectionStringBuilder(cs)
csb.ApplicationName = "all my logging info..."

ms access connect to 2 sql server databases on the same server

I am in the process of converting an Access application to use a SQL Server backend while still using the Access front end forms. Sounds like fun I know.
This application needs data access to 2 SQL Server databases that are on the same server. There are numerous inline sql query strings that attempt to connect to both databases at the same time on a single ADODB connection. This is failing because I am expecting records but none are returned.
What is the best way to fix this? Is there any way to use these sql strings or must it all be converted to stored procedures? Thanks for any help.
Here is some code:
Dim conn As ADODB.Connection
Set conn = New ADODB.Connection
Dim rst As ADODB.Recordset
Set rst = New ADODB.Recordset
With conn
.Provider = "sqlncli11"
.ConnectionString = "Server=[MY_SERVER];Database=[MY_DATABASE];User Id=sa; Password=password;"
.Open
End With
Dim str As String
str = "SELECT TABLE_DB1.Parent_Item_No FROM TABLE_DB1 INNER JOIN [DB2].[dbo].TABLE_DB2 ON (TABLE_DB1.Comp_Item_No = " & _
"TABLE_DB2.item_no) AND (TABLE_DB1.Loc = TABLE_DB2.loc) " & _
"GROUP BY TABLE_DB1.Parent_Item_No " & _
"HAVING (((TABLE_DB1.Parent_Item_No)='" & str_Assembly & "'));"
With rst
.Open str, conn, adOpenKeyset, adLockOptimistic ' this fails to return records
If .RecordCount > 0 Then
'Do Stuff
Else
'Do Other Stuff
End If
End With
You're only checking RecordCount. Take a look at this: slxdeveloper.com/page.aspx?action=viewarticle&articleid=33 Some recordset types don't populate the RecordCount property (adOpenKeyset should though). What happens if you use While Not .EOF and .BOF instead? What is that actual value of RecordCount in your code?
Would it at all be possible to run queries from SQL which save to an access file? I have nothing but trouble pulling data directly into access. I do have success when I set up an ODBC database and go to data -> get external data -> from other sources -> From microsoft query
Another method I myself have been successful with is using the power query add-on from microsoft. https://www.microsoft.com/en-us/download/details.aspx?id=39379
Despite this, what I still mostly end up doing is using the SQL import/export tool. I don't have screenshots or specific instructions as I'm not at work right now, but this can write directly to text files, Access databases, everything. I love it too much. Getting the correct drivers was a loop for sure. If you're on 64-bit and having issues then this is the driver you need. http://www.microsoft.com/en-us/download/details.aspx?id=13255
What I do is:
Set up my source (SQL 11 native client), choose the database you're pulling from
Specify an outfile type and location (I think it has to already exist)
When prompted to specify whether to pull data from tables and views or write a query, select write a query.
Go through the rest of the importer, you can edit the sql statement later on when viewing conversion and specify whether the transfer fails or ignores errors etc.
I personally still use the import export tool for transfers of all sizes because it's just so difficult to get all the correct drivers and get SQL to like what I want. (and without admin rights I get tired of asking my boss).
I hope one of those solutions can help you!
I've outline a more proper fix and a quick fix...
The more proper fix is the Data Layer Pattern. There is a lot to this fix and it may require some application structural changes. This is discussed in depth in another question:
Data Access Layer design patterns
A very simple fix is to use Access Linked tables. A Linked Table works like a normal Access table except the data is stored and updated on the SQL Server. Its basically a built in Data Access Layer to SQL Server. Its not an elegant solution but it gets you up and running right away. More info can be found here:
https://support.office.com/en-us/article/Import-or-link-to-SQL-Server-data-a5a3b4eb-57b9-45a0-b732-77bc6089b84e#bm2
On thing to be aware of with Linked Tables are that some Access Queries and Forms retrieve all the records before filtering and can lock the table so you can end up with some performance headaches if you have lots of data and lots of users.
Consider using the SQL server SYNONYM feature to add aliases for objects in one database to the other. Then just update all your queries to use one database.
Also, you could merge the two databases with each one, or one of them, going into a new schema to keep them separate. This could be tough if you have a lot of stored procedures, views, and functions in the database. This may be a terrible answer, but it could also be true that the two databases should never have been separate in the first place.
In the INNER JOIN, you prefixed the table name with DatabaseName.Schema.:
... FROM TABLE_DB1 INNER JOIN [DB2].[dbo].TABLE_DB2 ...
But you didn't do it in the other places where TABLE_DB2 occurs.
So you either need to change this:
ON (TABLE_DB1.Comp_Item_No = TABLE_DB2.item_no) AND (TABLE_DB1.Loc = TABLE_DB2.loc)
...to this:
ON (TABLE_DB1.Comp_Item_No = [DB2].[dbo].TABLE_DB2.item_no) AND (TABLE_DB1.Loc = [DB2].[dbo].TABLE_DB2.loc)
Or (which I prefer) you can use aliases for the table names in the FROM clause:
... FROM TABLE_DB1 t1 INNER JOIN [DB2].[dbo].TABLE_DB2 t2...
...then you use the aliases everywhere else:
str = "SELECT t1.Parent_Item_No FROM TABLE_DB1 t1 INNER JOIN [DB2].[dbo].TABLE_DB2 t2 ON (t1.Comp_Item_No = " & _
"t2.item_no) AND (t1.Loc = t2.loc) " & _
"GROUP BY t1.Parent_Item_No " & _
"HAVING (((t1.Parent_Item_No)='" & str_Assembly & "'));"
Additional background information:
If you connect to an SQL Server via ADO, you're directly connecting to exactly one database - the one in the connection string:
.ConnectionString = "Server=[MY_SERVER];Database=[MY_DATABASE];User Id=sa; Password=password;"
So in your case, the database you're connecting to is named MY_DATABASE. Any SQL you're executing via ADO goes to that database.
If you need to get data from other databases on the same server, you need to prefix the names with DatabaseName.Schema. in all places where you use them.
So let's assume we have:
a table MY_TABLE in MY_DATABASE
a table OTHER_TABLE in OTHER_DATABASE on the same server
both tables have the schema dbo (the default in SQL Server)
With the connection string from above (connecting to MY_DATABASE), you can join them as follows:
select *
from MY_TABLE
inner join OTHER_DATABASE.dbo.OTHER_TABLE
on MY_TABLE.SomeColumn = OTHER_DATABASE.dbo.OTHER_TABLE.OtherColumn
where OTHER_DATABASE.dbo.OTHER_TABLE.EvenAnotherColumn = 'foo'
See? Everywhere I used OTHER_TABLE, I prefixed it with OTHER_DATABASE.dbo..
PS:
It's bad practice to use the sa user to connect to a database with an application. The sa user has the highest permissions possible.
You should either use Windows authentication or create a dedicated SQL user for your app.
Consider storing your SQL in a pass-through query instead of VBA code. You can apply your filter using a copy of the .sql property of the pass-through query's querydef object, modifying it with the criteria they enter in your form at runtime.

How to create Access database from a script

I would like to create an Access database from a script. Ideally, I would love something similar to the way SQL scripts can be used to create a SQL database.
Is this possible at all? Is there anything that would leverage the SQL scripts I already have? I want to create the same database structure as my SQL database.
Let me know if you need me to clarify anything. Thanks.
I ended up going with my own solution. I could not get either of the first two to work very well. I created two executables: one to create the database and one to run scripts.
For the application that creates the database, I added the COM reference "Microsoft ADO Ext. 2.8 for DDL and Security". The code is actually quite simple: (Replace "test.mdb" with the proper file path for your file.)
Dim cat As ADOX.Catalog = New ADOX.Catalog()
cat.Create("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=test.mdb;Jet OLEDB:Engine Type=5")
To run the scripts, I created a simple parser to read and run "Access scripts". These scripts are based on SQL scripts, in that they provide a list of commands to run. For example, a script might be defined as:
--Create the table.
CREATE TABLE [Test] ([ID] Number, [Foo] Text(255))
--Add data to the table.
INSERT INTO [Test] ([ID], [Foo]) VALUES (1, 'Bar')
Here is the code for the parser. (Replace "test.mdb" with the proper file path for your file.)
Dim textStream = File.OpenText(scriptPath)
Dim lines As List(Of String) = New List(Of String)
While textStream.Peek() <> -1
lines.Add(textStream.ReadLine())
End While
textStream.Close()
Dim connection As OleDb.OleDbConnection = New OleDb.OleDbConnection("PROVIDER=Microsoft.Jet.OLEDB.4.0;Data Source=test.mdb")
connection.Open()
For Each line As String In lines
If Not String.IsNullOrEmpty(line) Then
If Not line.StartsWith("--") Then
Dim dbCommand = New OleDb.OleDbCommand(line, connection)
dbCommand.ExecuteNonQuery()
End If
End If
Next
connection.Close()
This solution works well and was pretty simple to implement.
It is possible to create an access database by code, either with DDL instructions of by manipulating ADO or DAO objects.
I doubt that DDL T-SQL code can be of any use to create an Access database: lots of instructions will not be understood in Access, from field types to indexes and constraints.
One option would be to use ADODB connections to connect both to the original SQL database and the newly created Access database (see #HansUp proposal), and use ADOX Object Model. You'll then be able to 'read' the SQL database (ie the ADOX Catalog) and its objects and recreate objects with 'similar' properties on the Access side: tables, fields, indexes, relations, etc.
Something similar could be done with DAO Object Model, but I guess it will be easier with ADOX.
Another option would be to check if existing softwares can do the trick. EMS SQL Manager is an option.

Search Query - SQL Server 2005 - Ideas - Knowledge Sharing

Currently I am designing a database schema where one table will contains details about all students of a university.
I am thinking the way how can I create the search engine query for administrators where they will search for students. (Some properties are Age, Location, Name, Surname etc etc) (approx 20 properties - 1 table)
My idea is to create the sql query dynamically from the code side. Is it the best way or is there any other better ways?
Shall I use a stored procedure?
Is there any other ways?
feel free to share
I am going to assume you have a front end that collects user input, executes a query and returns a result. I would say you HAVE to create the query dynamically from the code side. At the very least you will need to pass in variables that the user selected to query by. I would probably create a method that takes in the key/value search data and use that to execute the query. Because it will only be one table there would probably be no need for a view or stored procedure. I think a simple select statement including your search criteria will work fine.
I would suggest you to use LINQ to SQL and this will allow you to write such queries just in C# code without any SQL procedures. LINQ to SQL will care about security and prevent SQL injections
p.s.
Do not ever compose SQL from concatenated strings like SQL = "select * from table where " + "param1=" + param1 ... :)

Using Sqlite InMemory DB for unittesting MSSQL-DB

I am trying to implement this solution:
NHibernate-20-SQLite-and-In-Memory-Databases
The only problem is that we have hbms like this:
<class name="aTable" table="[dbo].[aTable]" mutable="true" lazy="false">
with [dbo] in the table name, because we are working with mssql, and this does not work with Sqlite.
I found this posting on the rhino-tools-dev group where they talk about just removing the schema from the mapping, but on NH2 there doesn't seem to be a classMapping.Schema.
There is a classMapping.Table.Schema, but it seems to be read-only. For example, this doesn't work:
foreach (PersistentClass cp in configuration.ClassMappings) {
// Does not work - throws a
//System.IndexOutOfRangeException: Index was outside the bounds of the array.
cp.Table.Schema = "";
}
Is there a way to tell Sqlite to ignore the [dbo] (I tried attach database :memory: as dbo, but this didn't seem to help)?
Alternatively, can I programmatically remove it from the classmappings (unfortunately changing the hbms is not possible right now)?
We had too many problems with SQLite which eventually pushed us to switch to SQL Express.
Problems I remember:
SQLite, when used in-memory, discards the database when Session is closed
SQLite does not support bunch of SQL constructs such basic ones as ISNULL, but also more advanced like common table expressions and others added in SQL 2005 and 2008. This becomes important when you start writing complex named queries.
SQLite's datetime has bigger range of possible values than SQL Server's
The API NHibernate uses for SQLite behaves differently than ADO.NET for MS SQL Server when used in scope of transaction. One example is the hbm-to-ddl tool whose Execute method does not work inside transaction with SQL Server but works fine with SQLite.
To summarize, SQLite-based unit-testing is very far from being conclusively representative of the issues you'll encounter when using MS SQL Server in PROD and therefore undermines the credibility of unit-testing overall.
We are using Sqlite to run unit tests with NH 2.0.1. Actually, I didn't run into this problem. I just didn't specify dbo, I think it is default on SqlServer.
By the way, there is a default_schema parameter in the configuration file. This is actually the database name, but you can try putting the dbo there, only for the SqlServer configuration of course.
After looking through the source of NH and some experimenting i think i found a simple workaround -
foreach (PersistentClass cp in configuration.ClassMappings)
{
// Input : [dbo].[Tablename] Output : Tablename
cp.Table.Name = Regex.Replace(cp.Table.Name, #"^\[.*\]\.\[", "");
cp.Table.Name = Regex.Replace(cp.Table.Name, #"\]$", "");
// just to be sure
cp.Table.Schema = null;
}
note that i can set Table.Schema to null while an empty string threw an exception ...
thanks for the answers !

Resources