Code to generate SQL Server table schema from ADO.NET - sql-server

I'd quite like to use ADO.NET to generate a CREATE TABLE script to create an exact copy of a given table.
The reason for this is persistence testing. I would like to know whether my application will persist to a particular database. I would like to be able to point the app to the database and table in question, and then the app will generate a new database with an exact copy of the specified table. Thus, persistence testing can take place against the cloned table without touching the original database, and when I'm done the new database can simply be dropped.
Before I embark on this ambitious project, I would like to know if anything already exists. I've tried Google, but all I can find are ways to get schema generation SQL through the SSMS UI, not through code.

You can use SQL Management Objects (SMO) for this.
Example (C#)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SqlServer.Management.Smo;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Server srv = new Server(#".\SQLEXPRESS");
Database db = srv.Databases["MyDB"];
Scripter scrp = new Scripter(srv);
scrp.Options.ScriptDrops = false;
scrp.Options.WithDependencies = true;
//Iterate through the tables in database and script each one. Display the script.
//Note that the StringCollection type needs the System.Collections.Specialized namespace to be included.
Microsoft.SqlServer.Management.Sdk.Sfc.Urn[] smoObjects = new Microsoft.SqlServer.Management.Sdk.Sfc.Urn[1];
foreach (Table tb in db.Tables)
{
smoObjects[0] = tb.Urn;
if (tb.IsSystemObject == false)
{
System.Collections.Specialized.StringCollection sc;
sc = scrp.Script(smoObjects);
foreach (string st in sc)
Console.WriteLine(st);
}
}
Console.ReadKey();
}
}
}

Related

NUnit Integration Tests on Web API - how to create/destroy integration test db

I'm implementing NUnit Integration Tests of our controller REST endpoints in a .NET Web API 2 project. We use an Entity Framework code-first from database approach to create our controllers and models.
I've got the myProjectIntegrationTests project set up, with NUnit installed and a reference to myProject.
From my research, the next step is to create a TestSetup script which, on each test, creates an Integration Tests Database in a LocalDb. This allows us to integration test our API calls without affecting the master dev database.
This TestSetup script should do several things each time a test runs:
- check if a connection is currently open in Integration Test Db - if so, close it.
- check if an existing Integration Test db exists - if so, tear it down.
- run a migration from my master dev database to my Integration Test Db to load it with real data.
- create a new instance of Integration Test Db
- integration tests run...
- close Integration Test Db connections
- teardown Integration Test Db
Creating this TestSetup class is what's giving me trouble. I've found tutorials on how to do this for .NET MVC, .NET Core and also Entity Framework - but none of these seem to be utilizing just .Net Web API, so some of the libraries and code being referenced isn't working for me. Can someone provide an example script or tutorial link that might work in .NET Web API 2?
Here's an example of someone doing this for EntityFramework, using I believe .Net Core. This is part of a great PluralSight tutorial on integration testing in Entity Framework by Michael Perry, found here:
using Globalmantics.DAL;
using Globalmantics.DAL.Migrations;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Data.E ntity;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Reflection;
namespace Globalmantics.IntegrationTests
{
[SetUpFixture]
public class TestSetup
{
[OneTimeSetUp]
public void SetUpDatabase()
{
DestroyDatabase();
CreateDatabase();
}
[OneTimeTearDown]
public void TearDownDatabase()
{
DestroyDatabase();
}
private static void CreateDatabase()
{
ExecuteSqlCommand(Master, $#"
CREATE DATABASE [Globalmantics]
ON (NAME = 'Globalmantics',
FILENAME = '{Filename}')");
var migration = new MigrateDatabaseToLatestVersion<
GlobalmanticsContext, GlobalmanticsConfiguration>();
migration.InitializeDatabase(new GlobalmanticsContext());
}
private static void DestroyDatabase()
{
var fileNames = ExecuteSqlQuery(Master, #"
SELECT [physical_name] FROM [sys].[master_files]
WHERE [database_id] = DB_ID('Globalmantics')",
row => (string)row["physical_name"]);
if (fileNames.Any())
{
ExecuteSqlCommand(Master, #"
ALTER DATABASE [Globalmantics] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
EXEC sp_detach_db 'Globalmantics'");
fileNames.ForEach(File.Delete);
}
}
private static void ExecuteSqlCommand(
SqlConnectionStringBuilder connectionStringBuilder,
string commandText)
{
using (var connection = new SqlConnection(connectionStringBuilder.ConnectionString))
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = commandText;
command.ExecuteNonQuery();
}
}
}
private static List<T> ExecuteSqlQuery<T>(
SqlConnectionStringBuilder connectionStringBuilder,
string queryText,
Func<SqlDataReader, T> read)
{
var result = new List<T>();
using (var connection = new SqlConnection(connectionStringBuilder.ConnectionString))
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = queryText;
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
result.Add(read(reader));
}
}
}
}
return result;
}
private static SqlConnectionStringBuilder Master =>
new SqlConnectionStringBuilder
{
DataSource = #"(LocalDB)\MSSQLLocalDB",
InitialCatalog = "master",
IntegratedSecurity = true
};
private static string Filename => Path.Combine(
Path.GetDirectoryName(
Assembly.GetExecutingAssembly().Location),
"Globalmantics.mdf");
}
}
And here's an older example of someone doing this for .Net MVC:
using System;
using System.Data.Entity;
using NUnit.Framework;
namespace BankingSite.IntegrationTests
{
[SetUpFixture]
public class TestFixtureLifecycle
{
public TestFixtureLifecycle()
{
EnsureDataDirectoryConnectionStringPlaceholderIsSet();
EnsureNoExistingDatabaseFiles();
}
private static void EnsureDataDirectoryConnectionStringPlaceholderIsSet()
{
// When not running inside MVC application the |DataDirectory| placeholder
// is null in a connection string, e.g AttachDBFilename=|DataDirectory|\TestBankingSiteDb.mdf
AppDomain.CurrentDomain.SetData("DataDirectory", NUnit.Framework.TestContext.CurrentContext.TestDirectory);
}
private void EnsureNoExistingDatabaseFiles()
{
const string connectionString = "name=DefaultConnection";
if (Database.Exists(connectionString))
{
Database.Delete(connectionString);
}
}
}
}
Probably not the answer you are looking for but I have had success recently using the sql server docker image with docker compose.
You can fire up a database instance and delete the data volumes when the the image shuts down. Using the —rm switch on the docker run command will do that automatically for you.
If you are using dot net core you can setup another container to run your entity framework migrations and tests.
If you are using dotnet framework you maybe be able to run windows docker images however they tend to be a bit slower to startup.
This approach would work best if you launched everything from a powershell script. Launching the infrastructure from the code as you are looking to do could be tricky and perhaps more complex than it needs to be.
Going line-by-line through the type of sql commands you'll need for these operations is just going to be painful. You would benefit much better to just develop a stored procedure that does the tear-down/build-up steps. You appear to already have a start in that as I see you writing code around the statements. Then your integration test code would just need to call this procedure and wait for the setup to complete. Remember, You don't have to do everything in code.

Windows Forms save to dataset but not table [duplicate]

I have following C# code in a console application.
Whenever I debug the application and run the query1 (which inserts a new value into the database) and then run query2 (which displays all the entries in the database), I can see the new entry I inserted clearly. However, when I close the application and check the table in the database (in Visual Studio), it is gone. I have no idea why it is not saving.
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.SqlServerCe;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
try
{
string fileName = "FlowerShop.sdf";
string fileLocation = "|DataDirectory|\\";
DatabaseAccess dbAccess = new DatabaseAccess();
dbAccess.Connect(fileName, fileLocation);
Console.WriteLine("Connected to the following database:\n"+fileLocation + fileName+"\n");
string query = "Insert into Products(Name, UnitPrice, UnitsInStock) values('NewItem', 500, 90)";
string res = dbAccess.ExecuteQuery(query);
Console.WriteLine(res);
string query2 = "Select * from Products";
string res2 = dbAccess.QueryData(query2);
Console.WriteLine(res2);
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine(e);
Console.ReadLine();
}
}
}
class DatabaseAccess
{
private SqlCeConnection _connection;
public void Connect(string fileName, string fileLocation)
{
Connect(#"Data Source=" + fileLocation + fileName);
}
public void Connect(string connectionString)
{
_connection = new SqlCeConnection(connectionString);
}
public string QueryData(string query)
{
_connection.Open();
using (SqlCeDataAdapter da = new SqlCeDataAdapter(query, _connection))
using (DataSet ds = new DataSet("Data Set"))
{
da.Fill(ds);
_connection.Close();
return ds.Tables[0].ToReadableString(); // a extension method I created
}
}
public string ExecuteQuery(string query)
{
_connection.Open();
using (SqlCeCommand c = new SqlCeCommand(query, _connection))
{
int r = c.ExecuteNonQuery();
_connection.Close();
return r.ToString();
}
}
}
EDIT: Forgot to mention that I am using SQL Server Compact Edition 4 and VS2012 Express.
It is a quite common problem. You use the |DataDirectory| substitution string. This means that, while debugging your app in the Visual Studio environment, the database used by your application is located in the subfolder BIN\DEBUG folder (or x86 variant) of your project. And this works well as you don't have any kind of error connecting to the database and making update operations.
But then, you exit the debug session and you look at your database through the Visual Studio Server Explorer (or any other suitable tool). This window has a different connection string (probably pointing to the copy of your database in the project folder). You search your tables and you don't see the changes.
Then the problem get worse. You restart VS to go hunting for the bug in your app, but you have your database file listed between your project files and the property Copy to Output directory is set to Copy Always. At this point Visual Studio obliges and copies the original database file from the project folder to the output folder (BIN\DEBUG) and thus your previous changes are lost.
Now, your application inserts/updates again the target table, you again can't find any error in your code and restart the loop again until you decide to post or search on StackOverflow.
You could stop this problem by clicking on the database file listed in your Solution Explorer and changing the property Copy To Output Directory to Copy If Newer or Never Copy. Also you could update your connectionstring in the Server Explorer to look at the working copy of your database or create a second connection. The first one still points to the database in the project folder while the second one points to the database in the BIN\DEBUG folder. In this way you could keep the original database ready for deployment purposes and schema changes, while, with the second connection you could look at the effective results of your coding efforts.
EDIT Special warning for MS-Access database users. The simple act of looking at your table changes the modified date of your database ALSO if you don't write or change anything. So the flag Copy if Newer kicks in and the database file is copied to the output directory. With Access better use Copy Never.
Committing changes / saving changes across debug sessions is a familiar topic in SQL CE forums. It is something that trips up quite a few people. I'll post links to source articles below, but I wanted to paste the answer that seems to get the best results to the most people:
You have several options to change this behavior. If your sdf file is part of the content of your project, this will affect how data is persisted. Remember that when you debug, all output of your project (including the sdf) if in the bin/debug folder.
You can decide not to include the sdf file as part of your project and manage the file location runtime.
If you are using "copy if newer", and project changes you make to the database will overwrite any runtime/debug changes.
If you are using "Do not copy", you will have to specify the location in code (as two levels above where your program is running).
If you have "Copy always", any changes made during runtime will always be overwritten
Answer Source
Here is a link to some further discussion and how to documentation.

Entity framework connects to master database for contained database user

I have a contained database user. Since it's contained in the database it's not allowed to connect to any other database including master. Unfortunately Entity Framework seems to connect to the master database anyway.
I've created a new console app with the latest Entity Framework nuget (6.2.0) to make sure nothing else connects to the master database:
static void Main(string[] args)
{
var connectionString = "Server=sql-azure.database.windows.net;Database='Database';User ID=Username;Password=password;Trusted_Connection=False;";
using (var dbContext = new DbContext(connectionString))
{
dbContext.Database.CommandTimeout = 10 * 60;
dbContext.Database.ExecuteSqlCommand("EXEC cleanup #Date", new SqlParameter("#Date", DateTime.UtcNow.AddMonths(-3)));
}
}
How do I force Entity Framework to not connect to the master database? I get failures in the audit logs on the master database which causes azure threat detection to go off.
After researching some more I've disabled the database initializer before the using statement like this:
Database.SetInitializer<DbContext>(null);
With this line of code, the console app doesn't connect to the master database any more. More info about Database.SetInitializer(null).
Full example:
static void Main(string[] args)
{
var connectionString = "Server=sql-azure.database.windows.net;Database='Database';User ID=Username;Password=password;Trusted_Connection=False;";
Database.SetInitializer<DbContext>(null);
using (var dbContext = new DbContext(connectionString))
{
dbContext.Database.CommandTimeout = 10 * 60;
dbContext.Database.ExecuteSqlCommand("EXEC cleanup #Date", new SqlParameter("#Date", DateTime.UtcNow.AddMonths(-3)));
}
}
I can't repro that:
Contained user:
//create user joe with password ='xxxxxx'
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Linq;
namespace Ef6Test
{
class Program
{
static void Main(string[] args)
{
var connectionString = "server=xxxxxxxxx.database.windows.net;database=adventureworks;uid=joe;pwd=xxxx";
using (var dbContext = new DbContext(connectionString))
{
dbContext.Database.CommandTimeout = 10 * 60;
Console.WriteLine(dbContext.Database.SqlQuery<string>("select db_name() dbname;").Single());
}
Console.WriteLine("Hit any key to exit");
Console.ReadKey();
}
}
}
The below would work for MS SQL on premises as well as if you are on SQL Azure:
use master;
CREATE LOGIN DemoUser WITH PASSWORD = 'DemoPassword';
GO
CREATE USER DemoUser FOR LOGIN DemoUser
GO
use DemoDB;
CREATE USER DemoUser FOR LOGIN DemoUser WITH DEFAULT_SCHEMA=[dbo]
GO
ALTER ROLE db_datareader ADD MEMBER DemoUser;
ALTER ROLE db_datawriter ADD MEMBER DemoUser;

Listing primary keys in Fox Pro with the OLE DB Provider?

How does one list the primary keys of a table in Fox Pro with the OLE DB Provider?
Using C# and switching my build to x86 instead of x64 I was able to use oledb provider for Fox Pro to display some information about the table:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.OleDb;
using System.Data;
namespace obtainFoxSchema
{
class Program
{
static void Main(string[] args)
{
OleDbConnection connection = new OleDbConnection(
"Provider=VFPOLEDB.1;Data Source=X:\\FREETABLES\\DATA;"
);
connection.Open();
DataTable tables = connection.GetSchema(
System.Data.OleDb.OleDbMetaDataCollectionNames.Tables
);
foreach (System.Data.DataRow rowTables in tables.Rows)
{
Console.Out.WriteLine(rowTables["table_name"].ToString());
DataTable columns = connection.GetSchema(
System.Data.OleDb.OleDbMetaDataCollectionNames.Columns,
new String[] { null, null, rowTables["table_name"].ToString(), null }
);
foreach (System.Data.DataRow rowColumns in columns.Rows)
{
Console.Out.WriteLine(
rowTables["table_name"].ToString() + "." +
rowColumns["column_name"].ToString() + " = " +
rowColumns["data_type"].ToString()
);
}
}
Console.Out.WriteLine("stop");
}
}
}
But I really don't know where to look in the objects returned to find the primary keys or the foreign keys between tables.
Any ideas where that kind of thing might be?
And yes I found the code for this in another question, but I built the connection string myself using Excel 2007's Get External Data.
I saw your post on Twitter. I am answering this question as a VFP developer with very little experience in Visual Studio and C#.
Not sure if you need things programmatically or just need to get the details. Have you tried to add the database to the Server Explorer? According to the Visual FoxPro Help File...
To connect to a Visual FoxPro database or table through the Visual FoxPro OLE DB Provider
Open Visual Studio.
From the View menu, select Server Explorer.
In the Server Explorer pane, right-click Data Connections, and click Add Connection
In the Data Link Properties dialog box, click the Provider tab.
Select Microsoft OLE DB Provider for Visual FoxPro.
The Connection tab in the Data Link Properties dialog box appears.
If this is not helpful, there is a DDEX provider, but it might only work with a specific version of Visual Studio.
http://vfpx.codeplex.com/wikipage?title=Sedna&referringTitle=Home#DDEX
If you are using the Entity Framework, there is a provider:
http://vfpefprovider.codeplex.com/
Rick
You can get the Primary Keys and Foreign Keys from the connection.GetOleDbSchemaTable method.
Example:
using(var connection = new OleDbConnection(#"provider=vfpoledb;data source=c:\NorthwindData\Northwind.dbc")) {
connection.Open();
DataTable primaryKeys = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Primary_Keys, null);
DataTable foreignKeys = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Foreign_Keys, null);
}
However, the Primary Keys DataTable doesn't let you know if a Primary Key is an AutoInc. If you are interested in getting VFP specific schema information then you might want to try using VfpClient instead of the OleDb classes.
VfpClient Example:
using(var connection = new VfpConnection(#"c:\NorthwindData\Northwind.dbc")) {
connection.Open();
DataTable primaryKeys = connection.GetSchema(VfpConnection.SchemaNames.PrimaryKeys);
DataTable foreignKeys = connection.GetSchema(VfpConnection.SchemaNames.ForeignKeys);
}
btw... the VfpClient includes a DDEX Provider that works with VS2010 and VS2012.

How can I get SQL Server database properties from C# code?

I've a C# 4.0 console application and a SQL Server 2008 database up and running on database server.
Does somebody know if there is a way to get the database properties (like "Database Read-Only" ) from the C# code?
My guess is it should be, but I was not able to find out the accurate solution.
Thanks in advance
There are at least two ways to do it. One is to use the Database Metadata tables the other to use SQL Management objects in both cases there's lot of data there so you really need to know what you want. For example this is how you would get the "Database Read-Only" property you mentioned.
Using a SqlCommand against the MetaData
using (SqlConnection cnn = new SqlConnection("Data Source=.;Initial Catalog=master;Integrated Security=SSPI;"))
{
SqlCommand cmd = new SqlCommand("SELECT is_read_only FROM sys.filegroups",cnn);
cnn.Open();
var isReadOnly = cmd.ExecuteScalar();
Console.WriteLine(isReadOnly );
}
Using SMO
using System;
using Microsoft.SqlServer.Management.Smo;
namespace SMO_Test
{
class Program
{
static void Main(string[] args)
{
Server srv = new Server(); //Connection to the local SQL Server
Database db = srv.Databases["master"];
foreach (FileGroup fg in db.FileGroups)
{
Console.WriteLine(fg.ReadOnly);
}
}
}
}

Resources