2

プログラムで SqlClient を使用してデータベースを作成しています。アプリでは定期的に新しいデータベースを作成する必要がありますが、構造は同じです。そのため、ファイルに作成スクリプトがあり、一度に 1 行ずつ実行します。アプリの別の部分 (SubSonic を使用して記述) が、新しく作成されたデータベースを操作するためです。

私が抱えている問題は、データベースを正常に作成した後でも、データベースにアクセスしようとすると、ログインに失敗したことを示す例外が発生することです。しばらくして、このアクセスは成功します。私はこれを 5 秒に絞り込みました。以下のコードはそれを (ある種不自然な方法で) 示していますが、SubSonic がこの問題にまったく関与していないことも証明しました。

これは私が我慢する必要があるものですか、それとも私が正しくしていないことがありますか?

私のコードは次のとおりです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Data;
using System.Data.SqlClient;


namespace SqlConnTest
{
class Program
{
    static void Main(string[] args)
    {
        var x = new ContentDB();
        if (x.IsNew)
        {
            x.Dispose();
            System.Threading.Thread.Sleep(4500);
            Console.WriteLine("Second time around");
            x = new ContentDB();
        }
        Console.WriteLine("All done");
        Console.ReadKey();
    }
}

class ContentDB : IDisposable
{
    private bool disposed = false;

    public void Dispose()
    {
        Dispose(true);
    }
    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {

            }
            disposed = true;
        }
    }
    public bool IsNew {get;set;}


    public ContentDB()
    {
        SqlConnection conn = new SqlConnection("Data Source=.\\SQLEXPRESS;Initial Catalog=Arch;Persist Security Info=False;User ID=Brunner;Password=Brunn3r1x");
        try
        {
            conn.Open();
        }
        catch (SqlException ex)
        {
            Console.WriteLine("Arch database needs to be created. {0}", ex.Message);
            IsNew = true;
        }
        finally
        {
            if (conn.State == ConnectionState.Open)
                conn.Close();
            conn.Dispose();
        }
        if (IsNew)
            CreateDB();
    }

    private void CreateDB()
    {
        using (var SqlScriptReader = new StreamReader("c:\\temp\\create.sql"))
        {
            var conn = new SqlConnection("Data Source=.\\SQLEXPRESS;Initial Catalog=master;Persist Security Info=False;User ID=Brunner;Password=Brunn3r1x");
            conn.Open();
            string SqlCmd = SqlScriptReader.ReadLine();
            while (SqlCmd != null && SqlCmd != String.Empty)
            {
                try
                {
                    var cmd = new SqlCommand(SqlCmd,conn);
                    cmd.ExecuteNonQuery();
                    cmd.Dispose();
                }
                catch (SqlException ex)
                {
                    Console.WriteLine("SQL command {0} failed,\n{1}", SqlCmd,ex.Message);
                }
                SqlCmd = SqlScriptReader.ReadLine();
            }
            if (conn.State == ConnectionState.Open)
                conn.Close();
            conn.Dispose();
        }
        Console.WriteLine("CreateDB finished");
    }

}

}

.SQL ファイルの内容は次のとおりです。

USE [master]
CREATE DATABASE [Arch] ON  PRIMARY ( NAME = N'Arch', FILENAME = N'C:\temp\Arch.mdf', SIZE = 2048KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ) LOG ON ( NAME = N'Arch_log', FILENAME = N'C:\temp\Arch_log.ldf'  , SIZE = 1024KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)
USE [Arch]
CREATE TABLE [dbo].[RptContent] ([RptContentID]    [int]     IDENTITY(1,1) NOT NULL,   [RptContentBLOB]  [varbinary](max)        NOT NULL CONSTRAINT [PK_RptContent] PRIMARY KEY CLUSTERED ([RptContentID] ASC ) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]) ON [PRIMARY]

Arch データベースが存在しない状態で実行すると、次のようになります。

Arch database needs to be created. Cannot open database "Arch" requested by the
login. The login failed.
Login failed for user 'Brunner'.
CreateDB finished
Second time around
Arch database needs to be created. Cannot open database "Arch" requested by the
login. The login failed.
Login failed for user 'Brunner'.
SQL command CREATE DATABASE [Arch] ON  PRIMARY ( NAME = N'Arch', FILENAME = N'C:
\temp\Arch.mdf', SIZE = 2048KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ) LOG
ON ( NAME = N'Arch_log', FILENAME = N'C:\temp\Arch_log.ldf'  , SIZE = 1024KB , M
AXSIZE = 2048GB , FILEGROWTH = 10%) failed,
Database 'Arch' already exists. Choose a different database name.
SQL command CREATE TABLE [dbo].[RptContent] ([RptContentID]    [int]     IDENTIT
Y(1,1) NOT NULL,   [RptContentBLOB]  [varbinary](max)        NOT NULL CONSTRAINT
[PK_RptContent] PRIMARY KEY CLUSTERED ([RptContentID] ASC ) WITH (PAD_INDEX  =
OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON,
ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]) ON [PRIMARY] failed,
There is already an object named 'RptContent' in the database.
CreateDB finished
All done

5000 のスリープで実行すると、次のようになります。

Arch database needs to be created. Cannot open database "Arch" requested by the
login. The login failed.
Login failed for user 'Brunner'.
CreateDB finished
Second time around
All done

Arch データベースが既に存在する場合に実行すると、次のようになります。

All done

これが長い場合は申し訳ありません-私がやっていることと問題を示す短いバージョンのコードにそれを取り除こうとしました。

4

1 に答える 1

0

スレッドをスリープ状態にする代わりに、このタスクを作成できます。作成されたデータベースを検索するループを作成し、それが見つからない間はループします。

データベースが存在するかどうかを確認する方法: SQL Server にデータベースが存在するかどうかを確認する方法

パフォーマンス上の理由から、継続的に検索するのではなく、ループごとに (スレッド スリープのような) タイマーを設定する必要があります。平均時間は 5 秒とおっしゃっていたので、1 秒または 2 秒ごとにループしても問題ないかもしれません。

于 2013-11-10T04:18:38.073 に答える