【问题标题】:C# Detect Database format | DbProviderFactoryC# 检测数据库格式 |数据库提供者工厂
【发布时间】:2016-11-03 12:17:58
【问题描述】:

我的应用实际上使用SqlServerCe(Microsoft SqlServer Compact)。现在有了我的新更新,我换成了SQLite

现在我的问题是:每次用户要导入数据库时​​,他可以导入SqlServerCe 文件(旧备份)或SQLite(新备份)。如何检测我的DbConnection 需要哪个DbProviderFactory

旧方法(需要更新)

    /// <summary>
    /// Verifies the db if it is not corrupt! If the return value is <see cref="Nullable"/>, the DB is corrupt!
    /// </summary>
    /// <returns><see cref="Array"/> of <see cref="int"/>. The 1. index is Components.Count(), the 2 index is the Recipes.Count()!!</returns>
    [CanBeNull]
    public static int[] ImportDB_Verify()
    {
        try
        {
            SqlCeProviderFactory provider = new SqlCeProviderFactory();
            SqlCeConnectionStringBuilder connectionStringBuilder = new SqlCeConnectionStringBuilder
            {
                DataSource = "Path/to/foo.db"
            };
            int[] val = new int[2];
            using (DbConnection dbConnection = provider.CreateConnection())
            {
                dbConnection.ConnectionString = connectionStringBuilder.ConnectionString;
                dbConnection.Open();

                using (DbCommand dbCommand = dbConnection.CreateCommand("SELECT Count(*) FROM Components"))
                {
                    val[0] = (int)dbCommand.ExecuteScalar();
                }
                using (DbCommand dbCommand = dbConnection.CreateCommand("SELECT Count(*) FROM Recipes"))
                {
                    val[1] = (int)dbCommand.ExecuteScalar();
                }
            }
            return val;
        }
        catch (Exception ex)
        {
            _Logger.Error(ex);
            return null;
        }
    }

尝试捕捉“解决方案”

如果有更好的,请告诉我!

    /// <summary>
    /// Verifies the db if it is not corrupt! If the return value is <see cref="Nullable"/>, the DB is corrupt!
    /// </summary>
    /// <returns><see cref="Array"/> of <see cref="int"/>. The 1. index is components.Count(), the 2 index is the recipes.Count()!!</returns>
    [CanBeNull]
    public static int[] ImportDB_Verify()
    {
        int[] val = new int[2];

        Exception sqLiteException;

        try
        {
            SQLiteFactory provider = new SQLiteFactory();
            SQLiteConnectionStringBuilder connectionStringBuilder = new SQLiteConnectionStringBuilder
            {
                DataSource = Core.CommonAppDataPath + "tmp.HTdb"
            };
            using (DbConnection dbConnection = provider.CreateConnection())
            {

                dbConnection.ConnectionString = connectionStringBuilder.ConnectionString;
                dbConnection.Open();

                using (DbCommand dbCommand = dbConnection.CreateCommand("SELECT Count(*) FROM components;"))
                {
                    val[0] = (int)dbCommand.ExecuteScalar();
                }
                using (DbCommand dbCommand = dbConnection.CreateCommand("SELECT Count(*) FROM recipes;"))
                {
                    val[1] = (int)dbCommand.ExecuteScalar();
                }
            }

            return val;
        }
        catch (Exception ex)
        {
            sqLiteException = ex;
        }

        try
        {
            SqlCeProviderFactory provider = new SqlCeProviderFactory();
            SqlCeConnectionStringBuilder connectionStringBuilder = new SqlCeConnectionStringBuilder
            {
                DataSource = Core.CommonAppDataPath + "tmp.HTdb"
            };
            using (DbConnection dbConnection = provider.CreateConnection())
            {

                dbConnection.ConnectionString = connectionStringBuilder.ConnectionString;
                dbConnection.Open();

                using (DbCommand dbCommand = dbConnection.CreateCommand("SELECT Count(*) FROM Components;"))
                {
                    val[0] = (int)dbCommand.ExecuteScalar();
                }
                using (DbCommand dbCommand = dbConnection.CreateCommand("SELECT Count(*) FROM Recipes;"))
                {
                    val[1] = (int)dbCommand.ExecuteScalar();
                }
            }
            return val;
        }
        catch (Exception ex)
        {
            _Logger.Error(ex, $"Error while verifying the database. The SQLite Exception: {sqLiteException}");
            return null;
        }
    }

【问题讨论】:

  • 提醒一下:您可以使用SqlCeEngine.Verify方法验证SQL Ce数据库的完整性。

标签: c# sql sqlite


【解决方案1】:

打开文件并读取它的“幻数”。 SQLite 数据库以 ASCII 字符串“SQLite 格式”开头,据我所知,SQL Server CE .SDF 文件以 0x01 0x0F 0x00 0x00 开头,也就是说,如果它们看起来像 .MDF 文件。

所以是这样的:

byte[] buffer = new byte[4];

using (var fileStream = File.OpenRead(databasefile))
{
    fileStream.Read(buffer, 0, 4);  
}

if (buffer[0] == 83 // S
    && buffer[1] == 81 // Q
    && buffer[2] == 76 // L
    && buffer[3] == 105) // i
{
    // SQLite
}
else
{
    // Assume SQL Server CE
}

请注意,用户仍然可以为您的代码提供恰好以“SQLi”开头但不是 SQLite 文件的文本文件,因此您不能也不应该使用这种方法删除异常处理代码。

【讨论】:

  • 好建议,但是当我在十六进制编辑器中打开我的 SQLite 数据库时 (HxD) 我看到不同的值:53 51 4C 69
  • 那是因为它们是十六进制的,而这段代码中显示的数字是十进制的。
  • 这是一个好方法。但是我仍然需要异常处理,所以我不会使用它。还是谢谢你
  • 就像我在回答中所说的那样,不应该使用它来代替异常处理。这将用于确定数据库文件类型,该文件声称根据前四个字节。当文件以“SQLi”开头时,它肯定不是 SQL CE SDF 文件,但它可能是 SQLite 文件。
  • @CodeCaster 你说得对,忘了显示为 HEX。
【解决方案2】:

使用@CodeCaster 的回答:

public enum DBType { SQLite, SQLServerCe };

public static DBType GetDatabaseType(string filename)
{
    byte[] buffer = new byte[4];

    using (var fileStream = File.OpenRead(databasefile))
    {
        fileStream.Read(buffer, 0, 4);  
    }

    if (buffer[0] == 83 // S
        && buffer[1] == 81 // Q
        && buffer[2] == 76 // L
        && buffer[3] == 105) // i
    {
        return DBType.SQLite;
    }
    else
    {
        return DBType.SQLServerCe;
    }
}

public static int[] ImportDB_Verify()
{
    string dbFilePath = "someDatabaseFile"
    DBType detectedType = GetDatabaseType(dbFilePath);

    if(detectedType == DBType.SQLite)
        return VerifySQLiteDb(dbFilePath);
    else
        return VerifySQLServerCeDb(dbFilePath);
}

private static int[] VerifySQLiteDb(string dbFilePath)
{
    //...
    // exception handling etc.
}

private static int[] VerifySQLServerCeDb(string dbFilePath)
{
    //...
    // exception handling etc.
}

【讨论】:

  • @CodeCaster 感谢您的提示!这是避免不必要的数据库访问的好方法。
猜你喜欢
  • 2014-03-03
  • 1970-01-01
  • 1970-01-01
  • 2019-08-31
  • 2011-04-22
  • 1970-01-01
  • 2014-02-10
  • 1970-01-01
  • 2017-10-30
相关资源
最近更新 更多