C# SMO Script user permissions using script option permissions - sql-server

When using scripting option Permissions in SQL Server 2008 and above, the database creation script does not get scripted. Instead, an ALTER DATABASE statement is scripted.
I am using SQL Server 2008 and higher. Using C# SMO .Net assemblies v12.0.2000.8.
These are my script options:
ScriptingOptions so = new ScriptingOptions();
so.DriAll = true;
so.EnforceScriptingOptions = false;
so.IncludeDatabaseContext = true;
so.AllowSystemObjects = false;
so.IncludeHeaders = true;
so.IncludeIfNotExists = true;
so.Indexes = true;
so.NoCommandTerminator = false;
so.NoFileGroup = true;
// TODO: script user permissions
so.Permissions = true;
so.PrimaryObject = true;
so.SchemaQualify = true;
so.ScriptOwner = true;
so.ScriptSchema = true;
so.ScriptDrops = false;
so.Triggers = true;
//so.ExtendedProperties = true;
so.WithDependencies = false;
so.ScriptBatchTerminator = true;
so.TargetServerVersion = SqlServerVersion.Version105;
so.ContinueScriptingOnError = true;
I do not use a Transfer Object.
When I set Permissions to false, the CREATE DATABASE statement is generated. When I set Permissions to true, an ALTER DATABASE statement is scripted instead.
I want to be able to script the user permissions AND have the CREATE DATABASE statement included in the script instead of the ALTER DATABASE statement.

Related

Update Local and Web database from codeigniter website

I have a Codeigniter website that is hosted on a global server and connected to the global database.
I want to connect another database that is hosted locally(192.168.x.x).
Is there any way to achieve this?
In real-world CodeIgniter projects, developers need to work with multiple databases at the same time. This presents a unique challenge to developers. Since this is a common enough problem, CodeIgniter offers a simple solution for it.
In order to use multiple database connections in your CodeIgniter project, you just need to create multiple configuration arrays that simplify working with multiple databases.
The Default Configuration Array
Following is the structure of the default Codeigniter database configuration array:
$db['default']['hostname'] = 'localhost';
$db['default']['username'] = 'root';
$db['default']['password'] = '';
$db['default']['database'] = 'mydefaultdatabase';
$db['default']['dbdriver'] = 'mysql';
$db['default']['dbprefix'] = '';
$db['default']['pconnect'] = TRUE;
$db['default']['db_debug'] = FALSE;
$db['default']['cache_on'] = FALSE;
$db['default']['autoinit'] = FALSE;
$db['default']['stricton'] = FALSE;
$db['default']['cachedir'] = '';
$db['default']['char_set'] = 'utf8';
$db['default']['dbcollat'] = 'utf8_general_ci';
$db['default']['swap_pre'] = '';
So in order to create another database connection, you should create another configuration array. This array has to follow the same structure. Here is an example of the array:
$db['anotherdb']['hostname'] = 'XXX.XXX.X.XXX';
$db['anotherdb']['username'] = 'another_user';
$db['anotherdb']['password'] = '';
$db['anotherdb']['database'] = 'anotherdatabase';
$db['anotherdb']['dbdriver'] = 'mysql';
$db['anotherdb']['dbprefix'] = '';
$db['anotherdb']['pconnect'] = TRUE;
$db['anotherdb']['db_debug'] = FALSE;
$db['anotherdb']['cache_on'] = FALSE;
$db['anotherdb']['cachedir'] = '';
$db['anotherdb']['char_set'] = 'utf8';
$db['anotherdb']['dbcollat'] = 'utf8_general_ci';
$db['anotherdb']['swap_pre'] = '';
$db['anotherdb']['autoinit'] = FALSE;
$db['anotherdb']['stricton'] = FALSE;
Connect to the Right Database
At this point, you have two databases in your sample project. To connect to a specific database, you must specify the database name. Here is the proper syntax:
this->load->database(anotherdb, TRUE)
After connecting to the database, you can perform databse operations as shown below:
load 'anotherdatabase'
$this->legacy_db = $this->load->database(anotherdatabase, true);
Fetch result from 'mydefaultdatabase'
$this->legacy_db->select ('*');
$this->legacy_db->from ('mydefaultdatabase');
$query = $this->legacy_db->get();
$result = $query->result ();
Now if you need to work with the second database, you have to send the connection to a variable that is usable in your model function:
function db_calling_model_method()
{
$otherdb = $this->load->database('anotherdb', TRUE); // the TRUE paramater tells CI that you'd like to return the database object.
$query = $otherdb->select('column_one, column_two')->get('table');
var_dump($query);
}
Close the Connections
CodeIgniter does close the database connections after it determines that the code no longer need the connection. However, as a good practice, developers should close the connections explicitly. Here is how to take care of the issue:
$this->db->close(); // for default Connection
$this->legacy_db->close(); //

How do I make sure alla data is restored using SMO?

A restore performed with C# code using SMO objects restores fine when original database is in SIMPLE recovery mode. We got problems with one database where the restore missed all content from a certain table, where all data was inserted late in process. The database showed to be in BULK LOGGED recovery mode. After changing to SIMPLE and doing a new backup, it restored fine, using our code.
We have tried different settings on the restore object, but found none that fixes the problem. We are under the impression that the restoring ignores data in the log.
The basic restore looks like this:
sqlServer = new Server(new ServerConnection(instanceName));
restore = GetRestore();
restore.PercentComplete += PercentCompleteAction;
restore.Complete += CompleteAction;
restore.SqlRestore(sqlServer);
the GetRestore function is basically implemented like this:
restore = new Restore();
var deviceItem = new BackupDeviceItem(backupFileName, DeviceType.File);
restore.Devices.Add(deviceItem);
restore.Database = newDatabaseName;
restore.NoRecovery = false;
restore.Action = RestoreActionType.Database;
restore.ReplaceDatabase = false;
return restore;
There are no error messages - just missing content in one table.
Added try:
I took a guess at the solution below, but it didn't help:
restore.ReplaceDatabase = false;
restore.NoRecovery = true;
restore.Action = RestoreActionType.Database;
restore.SqlRestore(sqlServer);
restore.ReplaceDatabase = true;
restore.NoRecovery = true;
restore.Action = RestoreActionType.Log;
restore.SqlRestore(sqlServer);
restore.ReplaceDatabase = true;
restore.NoRecovery = false;
restore.Action = RestoreActionType.Files;
restore.SqlRestore(sqlServer);
You need select a correct FileNumber in your Log file, see this method can solve your problem:
public static void restaurarBackup(string pathFileBak)
{
SqlConnection conn = new SqlConnection(Connection.getCon());
Server smoServer = new Server(new ServerConnection(conn));
string localFilePath = pathFileBak;
string db_name = "ETrade";
string defaultFolderEtrade = #"C:\ETrade\";
Restore rs = new Restore();
rs.NoRecovery = false;
rs.ReplaceDatabase = true;
BackupDeviceItem bdi = default(BackupDeviceItem);
bdi = new BackupDeviceItem(localFilePath, DeviceType.File);
rs.Devices.Add(bdi);
DataTable dt = rs.ReadFileList(smoServer);
foreach (DataRow r in dt.Rows)
{
string logicalFilename = r.ItemArray[dt.Columns["LogicalName"].Ordinal].ToString();
string physicalFilename = defaultFolderEtrade + Path.GetFileName(r.ItemArray[dt.Columns["PhysicalName"].Ordinal].ToString());
rs.RelocateFiles.Add(new RelocateFile(logicalFilename, physicalFilename));
}
DataTable backupHeaders = rs.ReadBackupHeader(smoServer);
rs.FileNumber = Convert.ToInt32(backupHeaders.AsEnumerable().Max(backupInfo => backupInfo["Position"]));
rs.Database = db_name;
smoServer.KillAllProcesses(rs.Database);
Microsoft.SqlServer.Management.Smo.Database db = smoServer.Databases[rs.Database];
db.DatabaseOptions.UserAccess = DatabaseUserAccess.Single;
rs.SqlRestore(smoServer);
db = smoServer.Databases[rs.Database];
db.SetOnline();
smoServer.Refresh();
db.Refresh();
}
If you want look backups in your Log file, see this query:
SELECT database_name, name, backup_start_date,
backup_finish_date, datediff(mi, backup_start_date, backup_finish_date) [tempo (min)],
position, first_lsn, last_lsn, server_name, recovery_model,
type, cast(backup_size/1024/1024 as numeric(15,2)) [Tamanho (MB)], B.is_copy_only
FROM msdb.dbo.backupset B

SQL Server DAC FX SchemaComparison SchemaCompareDatabaseEndpoint fails with no IntegratedSecuirty

I am trying to find newly created tables in the target database on publishing. Using DAC Fx I am able to find the differences and delete the tables after moving the newly created table to another db.
I developed and tested the code with IntegratedSecurity. Started failing on machines with SQLServer logins.
The moment I toggle the IntegratedSecurity to true it works. Is it a bug?
private void Analyse()
{
try
{
var sourceDacpac = new SchemaCompareDacpacEndpoint(DacPacSrc);
var csb = new SqlConnectionStringBuilder(ConnectionString);
csb.IntegratedSecurity = false;
var targetDatabase =new SchemaCompareDatabaseEndpoint(csb.ToString());
var comparison = new SchemaComparison(sourceDacpac, targetDatabase);
comparison.Options.DropObjectsNotInSource = true;
var result = comparison.Compare();
if (result.GetErrors().Any())
{
throw new Exception("Compare failed " + result.GetErrors().FirstOrDefault().Message);
}
var delta = new List<string>();
if (result.Differences != null && result.Differences.Any())
{
var deltaTables = result.Differences.Where(x => x.Name == "Table" && x.UpdateAction == SchemaUpdateAction.Delete);
delta = deltaTables.Select(x => x.TargetObject.Name.ToString()).ToList();
}
FindingDeltaCompleted?.Invoke(this, new DeltaEventArgs(delta));
}
catch (Exception ex)
{
Logging.HandleException(ex);
}
}
Try setting Persist Security Info=True in the SQL Authentication connection string.
SSDT/DAC Fx saves connection strings in registry under HKEY_CURRENT_USER\SOFTWARE\Microsoft\SSDT\ConnectionStrings. When Persist Security Info=True is not set, it won't restore the password when loading the connection strings from registry.

How to programmatically export SQL schema using Microsoft.SqlServer.Management.Smo

I've built a simple utility in C# that uses Microsoft.SqlServer.Management.Smo objects to export a database schema. This has been working great until I added a full text index.
When it exports the SQL for creating a full text index it does not include the columns that are defined in the index. For example, suppose I have a table named "Recipes" with 2 columns included in the FT index named "RecipeName" "Description". Dumping the schema using my utility produces the following SQL:
CREATE FULLTEXT INDEX ON [dbo].[Recipes]
KEY INDEX [PK_Recipes]ON ([ft], FILEGROUP [PRIMARY])
WITH (CHANGE_TRACKING = AUTO, STOPLIST = SYSTEM)
What I expect to be dumped is this (notice the columns):
CREATE FULLTEXT INDEX ON [dbo].[Recipes](
[Description] LANGUAGE [English],
[RecipeName] LANGUAGE [English]
)
KEY INDEX [PK_Recipes]ON ([ft], FILEGROUP [PRIMARY])
WITH (CHANGE_TRACKING = AUTO, STOPLIST = SYSTEM)
Here's the C# that generates the schema from a database file:
static void GenerateScript(string sourceDbPath, string destinationScriptPath)
{
try
{
string connString = string.Format(#"Data Source=.;AttachDbFilename={0};Integrated Security=True;User Instance=True", sourceDbPath);
SqlConnection sqlConn = new SqlConnection(connString);
ServerConnection serverConn = new ServerConnection(sqlConn);
Server server = new Server(serverConn);
Database database = server.Databases[sourceDbPath];
Transfer transfer = new Transfer(database);
ScriptingOptions options = new ScriptingOptions();
options.AppendToFile = false; // Overwrite file
options.ClusteredIndexes = true;
options.Indexes = true;
options.DriAll = true;
options.Triggers = true;
options.Bindings = true;
options.Default = true;
options.IncludeDatabaseContext = false;
options.IncludeHeaders = true;
options.FullTextIndexes = true;
options.SchemaQualify = true;
options.SchemaQualifyForeignKeysReferences = true;
options.ScriptSchema = true;
options.ScriptData = false;
options.ScriptDrops = false;
options.FileName = destinationScriptPath;
transfer.Options = options;
transfer.CopyAllFullTextCatalogs = true;
transfer.CopyAllFullTextStopLists = true;
transfer.CopyAllTables = true;
transfer.ScriptTransfer();
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
Environment.Exit(-1);
}
}
Can anyone spot what I'm missing?
I was unable to find a combination of scripting options that would include the columns in the full text index create statement.
So instead I queried the database for the full text index information by executing the sp_help_fulltext_tables and sp_help_fulltext_columns stored procs. This allowed me to construct the statements by hand.
Not ideal but it works.

Codeigniter 2.0.3 with SQL Server Active Record

I'm working on upgrading a Codeigniter app I have running on 1.7.2 to 2.0.3 but I'm not able to connect to SQL Server . Both versions are running on the same server running php 5.2.10 and connecting to the same SQL Server.
This is the error from CI 2.0.3
Unable to connect to your database server using the provided settings.
Filename: core/Loader.php
Line Number: 260
This is the connection string I'm using which of course works on 1.7.2
$db['reports']['hostname'] = "mysqlserver";
$db['reports']['username'] = "sqluser";
$db['reports']['password'] = "sqlpass";
$db['reports']['database'] = "SQLReportDB";
$db['reports']['dbdriver'] = "mssql";
$db['reports']['dbprefix'] = "";
$db['reports']['pconnect'] = TRUE;
$db['reports']['db_debug'] = TRUE;
$db['reports']['cache_on'] = FALSE;
$db['reports']['cachedir'] = "";
$db['reports']['port'] = 972;
In the controller I call the connection with this
$report_db = $this->load->database('reports', TRUE);
Below is the function in the loader file where it reports the failure.
Line 260 is return DB($params, $active_record);
/**
* Database Loader
*
* #param string the DB credentials
* #param bool whether to return the DB object
* #param bool whether to enable active record (this allows us to override the config setting)
* #return object
*/
public function database($params = '', $return = FALSE, $active_record = NULL)
{
// Grab the super object
$CI =& get_instance();
// Do we even need to load the database class?
if (class_exists('CI_DB') AND $return == FALSE AND $active_record == NULL AND isset($CI->db) AND is_object($CI->db))
{
return FALSE;
}
require_once(BASEPATH.'database/DB.php');
if ($return === TRUE)
{
return DB($params, $active_record);
}
// Initialize the db variable. Needed to prevent
// reference errors with some configurations
$CI->db = '';
// Load the DB class
$CI->db =& DB($params, $active_record);
}
Here are some settings I use in connecting to a SQL Server you haven't listed. Might be required due to upgrade...
$db['default']['char_set'] = 'utf8';
$db['default']['dbcollat'] = 'utf8_general_ci';
$db['default']['swap_pre'] = '';
$db['default']['autoinit'] = TRUE;
$db['default']['stricton'] = FALSE;
$db['reports']['port'] is no longer valid
The port needs to be added to the end of the server
$db['reports']['hostname'] = "mysqlserver:972";

Resources