2

考虑以下带有 TestTable 和过程的 TestDb

USE TestDb
GO
--DROP TABLE dbo.TestTable
IF NOT EXISTS (SELECT 1 FROM sys.tables WHERE name = 'TestTable')
BEGIN
    CREATE TABLE dbo.TestTable
    (
        RecordId int NOT NULL IDENTITY(1,1) PRIMARY KEY
        , StringValue varchar(50) NULL
        , DateValue date NULL
        , DateTimeValue datetime NULL
        , MoneyValue money NULL
        , DecimalValue decimal(19,4) NULL
        , IntValue int NULL
        , BitValue bit NOT NULL
    )

    INSERT INTO dbo.TestTable
    SELECT 'Test', CAST(GETDATE() AS DATE), GETDATE(), 100.15, 100.0015, 100, 1
    UNION SELECT NULL, NULL, NULL, NULL, NULL, NULL, 0
END
GO
IF EXISTS (SELECT 1 FROM sys.procedures WHERE name = 'Get_TestTable')
    DROP PROCEDURE dbo.Get_TestTable
GO
CREATE PROCEDURE dbo.Get_TestTable (@RecordId int = NULL) AS WAITFOR DELAY '00:00:30'; SELECT * FROM dbo.TestTable WHERE RecordId = ISNULL(@RecordId,RecordId);
GO
EXEC dbo.Get_TestTable @RecordId = NULL

使用 WebMatrix 内置的数据库查询助手时,您可以执行以下操作:

@{
    string errorMessage = String.Empty;
    int? RecordId = null;
    IEnumerable<dynamic> rowsTestTable = null;

    try
    {
        using (Database db = Database.Open("TestDb"))
        {
            rowsTestTable = db.Query("EXEC dbo.Get_TestTable @RecordId=@0",RecordId);
        }
    }
    catch (Exception ex)
    {
        errorMessage = ex.Message;
    }
}
<!DOCTYPE html>

<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
        @if(errorMessage == String.Empty)
        {
            <table border="1">
                <thead>
                    <tr>
                        <th>RecordId</th>
                        <th>StringValue</th>
                        <th>DateValue</th>
                        <th>DateTimeValue</th>
                        <th>MoneyValue</th>
                        <th>DecimalValue</th>
                        <th>IntValue</th>
                        <th>BitValue</th>
                    </tr>
                </thead>
                <tbody>
                    @foreach(var row in rowsTestTable)
                    {
                        <tr>
                            <td>@row["RecordId"]</td>
                            <td>@row["StringValue"]</td>
                            <td>@if(@row["DateValue"] != null){@Html.Raw(String.Format("{0:MM/dd/yyyy}",@row["DateValue"]));}</td>
                            <td>@if(@row["DateTimeValue"] != null){@Html.Raw(String.Format("{0:MM/dd/yyyy hh:mm:ss.fff tt}",@row["DateTimeValue"]));}</td>
                            <td>@if(@row["MoneyValue"] != null){@Html.Raw(String.Format("{0:c}",@row["MoneyValue"]));}</td>
                            <td>@row["DecimalValue"]</td>
                            <td>@row["IntValue"]</td>
                            <td>@row["BitValue"]</td>
                        </tr>
                    }
                </tbody>
            </table>
        }
        <p>@errorMessage</p>

        <h4>No Additional Problem - On handling of DateValue</h4>
        @try
        {
            foreach(var row in rowsTestTable)
            {
                <p>@if(row.DateValue != null){@Html.Raw(DateTime.Parse(row.DateValue.ToString()))}</p>
            }
        }
        catch (Exception ex)
        {
            <p>@ex.Message</p>
        }

        <h4>No Additional Problem - On handling of MoneyValue (and other number values)</h4>
        @try
        {
            foreach(var row in rowsTestTable)
            {
                <p>@if(row.MoneyValue != null){@Html.Raw(Double.Parse(row.MoneyValue.ToString()))}</p>
            }
        }
        catch (Exception ex)
        {
            <p>@ex.Message</p>
        }
    </body>
</html>

这会导致超时过期错误,因为 WebMatrix Database.Query 帮助程序已修复默认的 30 秒 CommandTimeout。有没有办法将单个查询的默认值覆盖为 5 分钟?

在没有找到解决方案的情况下,我开始根据大量搜索创建自己的 SimpleQuery 帮助程序并尝试各种方法,直到最终找到我能够理解和适应的代码参考。

using System.Collections.Generic; // IEnumerable<dynamic>
using System.Data; // IDataRecord
using System.Data.SqlClient; // SqlConnection
using System.Dynamic; // DynamicObject

public class SimpleQuery
{
    public static IEnumerable<dynamic> Execute(string connectionString, string commandString, int commandTimeout)
    {
        using (var connection = new SqlConnection(connectionString))
        {
            using (var command = new SqlCommand(commandString, connection))
            {
                command.CommandTimeout = commandTimeout;
                connection.Open();
                using (SqlDataReader reader = command.ExecuteReader())
                {
                    foreach (IDataRecord record in reader)
                    {
                        yield return new DataRecordDynamicWrapper(record);
                    }
                }
                connection.Close();
            }
        }
    }

    public class DataRecordDynamicWrapper : DynamicObject
    {
        private IDataRecord _dataRecord;
        public DataRecordDynamicWrapper(IDataRecord dataRecord) { _dataRecord = dataRecord; }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            result = _dataRecord[binder.Name];
            return result != null;
        }
    }
}

因此,现在通过更改网络代码以使用新的 SimpleQuery 帮助器,我可以获得几乎相同的结果,但存在一些问题

@{
    string errorMessage = String.Empty;
    int? RecordId = null;
    IEnumerable<dynamic> rowsTestTable = null;

    try
    {
        string commandString = String.Format("dbo.Get_TestTable @RecordId={0}", RecordId == null ? "null" : RecordId.ToString()); // Problem 1: Have to use String.Format to embed the Parameters
        rowsTestTable = SimpleQuery.Execute(System.Configuration.ConfigurationManager.ConnectionStrings["TestDb"].ConnectionString,commandString,300);
        foreach(var row in rowsTestTable) { break; } // Problem 2: Have to force query execution here, so the error (if any) gets trapped here
    }
    catch (Exception ex)
    {
        errorMessage = ex.Message;
    }
}
<!DOCTYPE html>

<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
        @if(errorMessage == String.Empty)
        {
            <table border="1">
                <thead>
                    <tr>
                        <th>RecordId</th>
                        <th>StringValue</th>
                        <th>DateValue</th>
                        <th>DateTimeValue</th>
                        <th>MoneyValue</th>
                        <th>DecimalValue</th>
                        <th>IntValue</th>
                        <th>BitValue</th>
                    </tr>
                </thead>
                <tbody>
                    @foreach(var row in rowsTestTable)
                    {
                        <tr>
                            @*<td>@row["RecordId"]</td>*@  <!-- Problem 3: Can't reference as row["FieldName"], so if any field names have spaces or other special characters, can't reference -->
                            <td>@row.RecordId</td>
                            <td>@row.StringValue</td>
                            <td>@if(@row.DateValue != null){@Html.Raw(String.Format("{0:MM/dd/yyyy}",@row.DateValue));}</td>
                            <td>@if(@row.DateTimeValue != null){@Html.Raw(String.Format("{0:MM/dd/yyyy hh:mm:ss.fff tt}",@row.DateTimeValue));}</td>
                            <td>@if(@row.MoneyValue != null){@Html.Raw(String.Format("{0:c}",@row.MoneyValue));}</td>
                            <td>@row.DecimalValue</td>
                            <td>@row.IntValue</td>
                            <td>@row.BitValue</td>
                        </tr>
                    }
                </tbody>
            </table>
        }
        <p>@errorMessage</p>

        <h4>Additional Problem - Unexpected handling of DateValue</h4>
        @try
        {
            foreach(var row in rowsTestTable)
            {
                <p>@if(row.DateValue != null){@Html.Raw(DateTime.Parse(row.DateValue.ToString()))}</p>
            }
        }
        catch (Exception ex)
        {
            <p>@ex.Message</p>
        }

        <h4>Additional Problem - Unexpected handling of MoneyValue (and other number values)</h4>
        @try
        {
            foreach(var row in rowsTestTable)
            {
                <p>@if(row.MoneyValue != null){@Html.Raw(Double.Parse(row.MoneyValue.ToString()))}</p>
            }
        }
        catch (Exception ex)
        {
            <p>@ex.Message</p>
        }
    </body>
</html>

问题 1-3 在使用 SimpleQuery 帮助器的第二个 Web 代码中进行了注释。这些我可以解决,但我仍然在努力解决的是为什么没有检测到 Number 和 Date 值的 NULL 检查。

我会很感激帮助正确检测这些,所以我可以在使用 Double.Parse 或 DateTime.Parse 时避免随后的错误。对于 SimpleQuery 帮助程序或您看到的任何其他内容,我也将不胜感激。

提前致谢。

4

2 回答 2

1

您可以尝试切换到使用 Dapper。它具有与 WebMatrix.Data 非常相似的语法,IEnumerable<dynamic>如果您愿意,可以返回结果为强类型或强类型,并允许您在每个查询的基础上覆盖命令超时。

https://github.com/StackExchange/dapper-dot-net

于 2014-10-21T11:18:19.687 回答
0

在使用我的 SimpleQuery Helper 时使用以下内容可用于检测 Null 或 String.Empty,因为我的 Helper 中的值在转换为 ToString() 时以 String.Empty 形式出现,而来自 Database.Query 时,它们以 NULL 形式返回。

@try
{
    foreach(var row in rowsTestTable)
    {
        <p>@if(!String.IsNullOrEmpty(row.DateValue.ToString())){@Html.Raw(DateTime.Parse(row.DateValue.ToString()))}</p>
    }
}
catch (Exception ex)
{
    <p>@ex.Message</p>
}

因此,虽然这并没有向我解释为什么存在差异或如何使我的 SimpleQuery Helper 更等同于 Database.Query,但它确实帮助我解决了眼前的问题。

于 2014-10-21T20:53:57.517 回答