2014-10-20 2 views
0

Рассмотрим следующего TestDb с TestTable и процедуройWebMatrix Database.Query с пользовательским CommandTimeout

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 @[email protected]",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, основанного на многочисленных поисках и проверке вещей, пока не нашел наконец code reference, который я смог понять и адаптировать.

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. Это я могу обойти, но то, с чем я все еще боюсь, - это почему NULL-проверка не обнаружена для значений Number и Date.

Я был бы признателен за помощь в их правильном обнаружении, поэтому я могу избежать последующей ошибки при использовании Double.Parse или DateTime.Parse. Я также хотел бы оценить любые общие указатели/улучшения для помощника SimpleQuery или что-нибудь еще, что вы видите.

Заранее спасибо.

ответ

0

Вы можете попробовать переключиться на использование Dapper. Он имеет очень похожий синтаксис для WebMatrix.Data, может возвращать результаты как IEnumerable<dynamic> или строго типизирован, если вы предпочитаете, и позволяет переопределить тайм-аут команды для каждого запроса.

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

+0

Благодарим вас за обращение. Я буду смотреть в него. Я буду принимать ответ после решения моей проблемы. – cusman

0

Используя следующее при использовании моего SimpleQuery Helper работает на Детектирование Null или String.Empty, поскольку значения из моего помощника при преобразовании в 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, она помогает мне двигаться мимо насущной проблемой.

Смежные вопросы