Как получить сообщение об ошибке SQL и отобразить его с помощью ASP.NET Ядро MVC?

#sql-server #asp.net-core-mvc

#sql-сервер #asp.net-ядро-mvc

Вопрос:

Я хочу показать пользователю мою ошибку SQL Server. Когда метод возвращает значение, с этим кодом проблем нет.

Но когда записи нет, я хочу выдать сообщение об ошибке, которое извлекается из считывателя.

Вот что я пробовал:

Контроллер:

 public IActionResult Index()
{
        //It works ok when there is a retrieved date
        var expenses = context.GetAll(GetUserId());
        
        //I think it`s like this. But it says there is a problem with view.
        foreach (var item in expenses)
        {
            if (item.Error != null)
            {
                ViewBag.Error = item.Error;
                return View();
            }
        }
        return View(expenses);
    }
 

Я получаю эту ошибку:

Система.Исключение ArgumentNullException: значение не может быть нулевым.
Имя параметра: источник .

В моем представлении индекса, где я говорю:

 @if (Model.Any())
{
   html...
}
else
{
  Viewbag.Error
}
 

Метод C #:

 public IQueryable<Expenses> GetAll(string UserId)
{
        List<Expenses> expenses = new List<Expenses>();

        using (DALC.GetConnection())
        {
            DALC.Command("spGetUserExpenses");

            DALC.cmd.Parameters.Add("@UserId", SqlDbType.NVarChar).Value = UserId;
            using (SqlDataReader reader = DALC.cmd.ExecuteReader())
            {
                if (reader.HasRows)
                {
                    while (reader.Read())
                    {
                        Expenses entities = new Expenses
                        {
                            Id = Convert.ToInt32(reader["Id"]),
                            TotalAmount = Convert.ToDouble(reader["Amount"]),
                            Desription = reader["Notes"].ToString(),
                            Date = Convert.ToDateTime(reader["Date"]),
                            IsCash = Convert.ToBoolean(reader["IsCash"]),
                            IsCard = Convert.ToBoolean(reader["IsCard"])
                        };
                        expenses.Add(entities);
                    }
                }

                if (reader.NextResult())
                {
                    reader.Read();
                    //setting second select statement which is an error by my side?
                    expenses.Add(new Expenses { Error = reader[0].ToString() });
                }
            }
        }

        return expenses.AsQueryable();
}
 

Хранимая процедура:

 ALTER PROCEDURE [dbo].[spGetUserExpenses]
    @UserId nvarchar(450)
AS
BEGIN
    SELECT
        e.ID,
        e.Amount,
        e.Notes,
        e.[Date],
        e.IsCash,
        e.IsCard
    FROM
        Expenses e
    WHERE 
        UserId = @UserId
        AND DATENAME(YEAR, CAST(e.[Date] AS varchar)) = DATENAME(YEAR, GETDATE()) 
        AND DATENAME(MONTH, CAST(e.[Date] AS varchar)) = DATENAME(MONTH, GETDATE()) 
    ORDER BY 
        e.ID DESC

    IF (@@ROWCOUNT = 0)
    BEGIN
        SELECT N'No Expense Found'
    END
END
 

Комментарии:

1. Где возникает ошибка? Ожидает ли vewi действительный идентификатор? Помимо вашего вопроса: if (reader.HasRows) в этом нет необходимости. Также DATENAME(YEAR,... очень неэффективно, особенно против индекса, лучше сделать e.[Date] >= DATETIMEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1) AND e.[Date] < DATEADD(day, 1, EOMONTH(GETDATE())) примечание об использовании полуоткрытого интервала.

2. @Charlieface привет. Проблема была связана с хранимой процедурой. Я удалил те части, о которых вы мне рассказали, и это сработало. Но я не понял вашего предложения. Я хочу показать пользователю расходы текущего месяца.

3. Теперь ваша ошибка исправлена? Мое предложение состояло в том, чтобы просто использовать интервал дат, а не использовать функции в столбце даты, потому что функции означают, что он не будет использовать индекс.

4. @Charlieface да, теперь это работает. но я не знал, что связано с этим sp.

5. @Charlieface я.paste.pics/BAIBA.png посмотри, что говорится в твоем предложении

Ответ №1:

Я предпочитаю этот способ выбора данных из хранимых процедур, он работает для меня

 connection = new SqlConnection(connectionString);
                connection.Open();
                SqlCommand com = new SqlCommand("spGetUserExpenses", connection);
                com.CommandType = CommandType.StoredProcedure;
    
                //CARA 1
                if (userid == null)
                {
                    com.Parameters.AddWithValue("@UserId", DBNull.Value)
                }
                else
                {
                    com.Parameters.AddWithValue("@UserId", UserId)
                }
    
    IDataReader reader = com.ExecuteReader();
    
                while (reader.Read())
                {
                    Expenses entities = new Expenses()
                    {
                        Id = Convert.ToInt32(reader["Id"]),
                                TotalAmount = Convert.ToDouble(reader["Amount"]),
                                Desription = reader["Notes"].ToString(),
                                Date = Convert.ToDateTime(reader["Date"]),
                                IsCash = Convert.ToBoolean(reader["IsCash"]),
                                IsCard = Convert.ToBoolean(reader["IsCard"])
                    };
    
                    expenses.Add(entities);
                }
    
                reader.Close();
                connection.Close();
    
                return expenses;
 

Комментарии:

1. Где ваши using блоки?

2. я сказал, что нет проблем с кодом, когда извлекаются данные..