SMO scripting objects and security - c#

I have a customer that has a SQL database on a hosted server; call the db "myDatabase".
The hosting co. has locked down object explorer - I can't see myDatabase in the database listed (I see tempdb and master). However, if I "use myDatabase" and then "select * from myTable", all works fine.
Since we have no access to object explorer, I can't right click and generate scripts. I thought that I might be able to use SMO to accomplish what I want, but when I attempt something similar to this:
Server myServer = new Server(conn);
Database myDB = server.Databases["myDatabase"];
Table myTbl = myDB.Tables["myTable"];
It fails - myDB is null (when I iterate through the databases collection, as expected, I only see master and tempdb - the db's I can see in object explorer). It obviously has to do with security - if I can't see the table in object explorer, it won't let me access it through SMO. Anyone have any ideas of a workaround or alternate method to allow me to generate a script?
Thx!

I haven't looked at the SMO code, but have you tried using the constructor on the database object? Maybe you can access it directly.
Database myDB = new Database(myServer, "myDatabase");

Is the myDb.Tables collection empty? Could it be that you are referencing it using the wrong name?
One option you could try is to use Linq2Sql to generate a model of the database. You can then use the model to create a new database that should be more or less identical to the original. Look up the DataContext.CreateDatabase method for more info.
Another option would be to list all tables using the following query:
select * from sys.tables
And then listing all columns in the tables using the following:
select * from sys.columns where object_id = (object id from the previous query)
This will give you all tables and columns defined in your database and should be enough to create the database structure. In addition you have system views for other objects defined as well.

Related

How to obtain a view's structure/query using OleDb?

I have an ASP.Net application that reads data from an Access 2010 database file (.mdb).
I can easily list all tables and views in the database like this:
string sql = "select name from msysobjects where type in (1,5)";
OleDbCommand cmd = new OleDbCommand(sql,con);
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
da.Fill(dataTable); // now dataTable contains all ojbects' names I have created in access
What I would like to inquire about is the structure of the tables/views without relying on Access. I.E, using external OleDb commands.
In Oracle, I could do so by running the command
describe table_name;
describe view_name;
describe procedure_name;
but how can it be done in MS Access?
As with all relational databases there are tables of tables (reflection data). These are normally hidden, but you can Select * From msysObjects. Filtering on Type will allow you to distinguish tables from queries from forms from reports, but also allows distinguishing internal tables from mapped tables.
If you want them listed in the Navigation Pane, then right-click on the pane, select Navigation Options, and click the Show System Objects check box.

Same query with the same query plan takes ~10x longer when executed from ADO.NET vs. SMSS

My query is fairly complex, but I have simplified it to figure out this problem and now it is a simple JOIN that I'm running on a SQL Server 2014 database. The query is:
SELECT * FROM SportsCars as sc INNER JOIN Cars AS c ON c.CarID = sc.CarID WHERE c.Type = 1
When I run this query from SMSS and watch it in SQL Profiler, it takes around 350ms to execute. When I run the same query inside my application using Entity Framework or ADO.NET (I've tried both). It takes 4500ms to execute.
ADO.NET Code:
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
var cmdA = new SqlCommand("SET ARITHABORT ON", connection);
cmdA.ExecuteNonQuery();
var query = "SELECT * FROM SportsCars as sc INNER JOIN Cars AS c ON c.CarID = sc.CarID WHERE c.Type = 1";
var cmd = new SqlCommand(query, connection);
cmd.ExecuteNonQuery()
}
I've done an extensive Google search and found this awesome article and several StackOverflow questions (here and here). In order to make the session parameters identical for both queries I call SET ARITHABORT ON in ADO.NET and it makes no difference. This is a straight SQL query, so there is not a parameter sniffing problem. I've simplified the query and the indexes down to their most basic form for this test. There is nothing else running on the server and there is nothing else accessing the database during the test. There are no computed columns in the Cars or SportsCars table, just INTs and VARCHARs.
The SportsCars table has about 170k records and 4 columns, and the Cars table has about 1.2M records and 7 columns. The resulting data set (SportsCars of Type=1) has about 2600 records and 11 columns. I have a single non-clustered index on the Cars table, on the [Type] column that includes all the columns of the cars table. And both tables have a clustered index on the CarID column. No other indexes exist on either table. I'm running as the same database user in both cases.
When I view the data in SQL Profiler, I see that both queries are using the exact same, very simple query plan. In SQL Profiler, I'm using the Performance Event Class and the ShowPlan XML Statistics Profile, which I believe to be the proper event to monitor and capture the actual execution plan. The # of reads is the same for both queries (2596).
How can two exact same queries with the exact same query plan take 10x longer in ADO.NET vs. SMSS?
Figured it out:
Because I'm using Entity Framework, the connection string in my application has MultipleActiveResultSets=True. When I remove this from the connection string, the queries have the same performance in ADO.NET and SSMS.
Apparently there is an issue with this setting causing queries to respond slowly when connected to SQL Server via WAN. I found this link and this comment:
MARS uses "firehose mode" to retrieve data. Firehose mode means that
the server will produce data as fast as possible. This also means that
your client application must receive inbound data at the same speed as
it comes in. If it doesn't the data storage buffers on the server will
fill up and the processing will stop until those buffers empty.
So what? You may ask... But as long as the processing is stopped the
resources on the SQL server are in use and are tied up. This includes
the worker thread, schema and data locks, memory, etc. So it is
crucial that your client application consumes the inbound results as
quickly as they arrive.
I have to use this setting with Entity Framework otherwise lazy loading will generate exceptions. So I'm going to have to figure out some other workaround. But at least I understand the issue now.
How can two exact same queries with the exact same query plan take 10x longer in ADO.NET vs. SMSS?
First we need to be clear about what is considered "same" with regards to queries and query plans. Assuming that the query at the very top of the question is a copy-and-paste, then it is not the same query as the one being submitted via ADO.NET. For two queries to be the same, they need to be byte-by-byte the same, which includes all white-space, capitalization, punctuation, comments, etc.
The two queries shown are definitely very similar. And they might even share the same execution plan. But how was "same"ness determined for those? Was the XML the same in both cases? Or just what was shown graphically in SSMS when viewing the plans? If they were determined to be the same based on their graphical representation then that is sometimes misleading. The XML itself needs to be checked. Even if two query plans have the same query hash, there are still (sometimes) parts of a query plan that are variable and changes do not change the plan hash. One example is the evaluation of expressions. Sometimes they are calculated and their result is embedded into the plan as a constant. Sometimes they are calculated at the start of each execution and stored and reused within that particular execution, but not for any subsequent executions.
One difference between SSMS and ADO.NET is the default session properties for each. I thought I had seen a chart years ago showing the defaults for ADO / OLEDB / SQLNCLI but can't find it out. Either way, it doesn't need to be guess work as it can be discovered using the SESSIONPROPERTY function. Just run this query in the C# code instead of your current SELECT, and inspect the results in debug or print them out or whatever. Either way, run something like this:
SELECT SESSIONPROPERTY('ANSI_NULLS') AS [AnsiNulls],
SESSIONPROPERTY('ANSI_PADDING') AS [AnsiPadding],
SESSIONPROPERTY('CONCAT_NULL_YIELDS_NULL') AS [ConcatNullYieldsNull],
...;
Make sure to get all of the setting noted in the linked MSDN page. Now, in SSMS, go to the "Query" menu, select "Query Options...", and go to "Execution" | "ANSI". The settings coming back from the C# code need to match the ones showing in SSMS. Anything set different requires adding something like this to the beginning of your ADO.NET query string:
SET ANSI_NULLS ON;
{rest of query}
Now, if you want to eliminate the DataTable loading from being a possible suspect, just replace that line, just replace:
var cars = new DataTable();
cars.Load(reader);
with:
while(reader.Read());
And lastly, why not just put the query into a Stored Procedure? The session settings (i.e. ANSI_NULLS, etc) that typically matter the most are stored with the proc definition so they should work the same whether you EXEC from SSMS or from ADO.NET (again, we aren't dealing with any parameters here).

Retrieve SQL Server database information in C#

Want to improve this post? Provide detailed answers to this question, including citations and an explanation of why your answer is correct. Answers without enough detail may be edited or deleted.
I'm trying to create a program which will generate a SQL database schema including tables, view, keys, indexes, triggers, etc... like:
CREATE TABLE TableName(....) ....
CREATE VIEW ViewName(...) ....
I know this is possible because SQL Server Management Studio does it (generate script command). However, how does it do it?
UPDATE: I forgot to mention about permissions: I'm an owner of database (in most cases) but I'm not sys-admin. Would there be any difference?
If you are targeting SQL Server only, SMO is very powerful. This is the library that SQL Server Management Studio uses, and contains classes to convert database objects into scripts.
The scripting example here is a great place to start.
for list of tables:
foreach (DataRow row in schemaTbl.Rows)
{
listBox.Items.Add(row["TABLE_NAME"]);
}
for columns from perticular table
object[] objArrRestrict;
objArrRestrict = new object[] {null, null, "Customers", null};
DataTable schemaCols;
schemaCols = con.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, objArrRestrict);
//List the schema info for the selected table
foreach (DataRow row in schemaCols.Rows)
{
listBox.Items.Add(row["COLUMN_NAME"]);
}
Queries of database structure vary by sql server version.
The 2008 R2 page is here, which links to a TABLES page, which links to a sys.tables page, which links to a sys.objects page.
The sys.objects page has relevant samples. This only gets you the table. There are other system objects for column, triggers, views, ...
If you truly mean generate you might want to look into Entity Framework / Code first approach that will essentially boostrap your db for you (Tables, etc).

SQLite Attach command and Linq to SQL

If you open a sqlite-database from a file you can later attach another file an give it a name, in case it contains equally named tables as the first database.
Using DataContext.GetTable() will return the table of type T from the "original" database. Is there a way to get the other table as well?
How would you do something like "INSERT INTO Person SELECT * FROM Source.Person" in linq, if "Source" is the database you attached?

LINQ to SQL using dynamic tables

I am developing application VS 2008, .NET 3.5 and I am trying to use LINQ To SQL. I drag & drop tables on the designer to generate the .dbml file.
The problem I have that I have some dynamic tables for search indexing.
I know the structure of table, only the application creates new tables like this:
Files_1_1, Files_1_2, ... Files_m_n
DataSearch_1_1, DataSearch_1_2, DataSearch_m_n
In this case, m and n are integers in the name of the table.
I statically define which columns are available but not the name of table, so I need a way to do this on the fly. Of course, this would also have to include associated tables.
I haven't been able to get good idea about it. I would also be satisfied with just being able to generate LINQ To SQL class for this tables.
Has anyone come across a solution to this problem? I have been looking through blog posts and forums for the past one days in vain. Any sample code is great for me.
Link to sql works with stored procedures and the designer will auto create a class for the return type. You could use dynamic sql in your sp and return linq to sql classes.
You could create a stored procedure like below:
CREATE PROCEDURE spGetFiles
(
#TableName
)
AS
EXEC('SELECT * FROM " + #TableName)
Then in the Visual Studio O/R designer, select the SP from the server explorer and drag it into the designer window in the same way that you add tables. A method with the same name as your SP will be created on your data context class and a class called something like spGetFilesReturnType will be created (i may have got this naming slightly wrong but you get the idea). You then just call the datacontext method with the table name as a string parameter and collections of spGetFilesReturnType objects will be returned.

Categories

Resources