Как вернуть null из запроса Dapper, а не по умолчанию (T)?

Я использую Dapper для некоторых вызовов базы данных только для чтения через хранимую процедуру. . У меня есть запрос, который либо вернет 1 строку, либо ничего.

Я использую Dapper следующим образом:

using (var conn = new SqlConnection(ConnectionString))
{
    conn.Open();

    return conn.Query<CaseOfficer>("API.GetCaseOfficer", 
        new { Reference = reference }, 
        commandType: CommandType.StoredProcedure).FirstOrDefault();
}

Возвращенный объект CaseOfficer выглядит следующим образом:

public class CaseOfficer
{
    public string Title { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public string Telephone { get; set; }
}

Затем он возвращается через приложение веб-API ASP.NET в виде JSON.

Когда хранимая процедура возвращает результат, я получаю следующее:

{
    title: "Mr",
    firstName: "Case",
    lastName: "Officer",
    email: "[email protected]",
    telephone: "01234 567890"
}

Но когда он ничего не возвращает, я получаю:

{
    title: null,
    firstName: null,
    lastName: null,
    email: null,
    telephone: null
}

Как я могу заставить Dapper возвращать null (чтобы я мог проверить и ответить 404), а не значение по умолчанию (CaseOfficer)?


person James Simm    schedule 30.07.2012    source источник
comment
К вашему сведению, значение по умолчанию (CaseOfficer) равно нулю. Похоже, он создает объект и просто не заполняет поля. Больше ничем помочь не могу, так как не знаю Даппера.   -  person aqwert    schedule 30.07.2012


Ответы (2)


Если ваш SP не вернет строку, то dapper не вернет строку; Итак, первое, что нужно проверить: возможно, ваш SP вернул пустую строку? Ряд всех nulls ? Или он вернул 0 строк?

Теперь, предполагая, что ни одна строка не была возвращена, FirstOrDefault (стандартная вещь LINQ-to-Objects) вернет null, если CaseOfficer является class, или экземпляр по умолчанию, если CaseOfficer является struct. Итак, далее: проверка CaseOfficer является class (я не могу придумать ни одной разумной причины, по которой это было бы struct).

Но: dapper с FirstOrDefault обычно уже делает то, что вы хотите.

person Marc Gravell    schedule 30.07.2012
comment
Судя по всему, SP возвращает строку из nulls. CaseOfficer — это класс. Посмотрим, смогу ли я изменить sproc, чтобы он возвращал 0 строк. - person James Simm; 30.07.2012
comment
@Джеймс, другой вариант - найти столбец, который должен иметь значение, и проверить его, например, .FirstOrDefault(x => x.FirstName != null) - person Marc Gravell; 30.07.2012
comment
Возвращает ли Dapper значение null, когда T является типом, допускающим значение null, например int?? - person Chris; 08.07.2015
comment
@MarcGravell, если мы используем Query‹T› для выполнения хранимой процедуры и если хранимая процедура не возвращает ни одной строки, Dapper возвращает IEnumerable со счетчиком 0. Как мы можем получить нуль, если из хранимой процедуры не возвращаются строки? Я не хочу инициализировать свой список с 0 записями. В таких случаях я хочу установить значение null. - person Priya; 15.04.2020
comment
@Priya, мне кажется, что dapper понимает это правильно ... пустая сетка не является нулевой - в ней просто нет строк; но: если это не то, что вы хотите, просто проверьте, являются ли это нулевыми строками, и если да, замените их в своем собственном коде на null. В этом сценарии у Dapper нет API для этого; если бы это был сценарий с одной строкой, вы могли бы использовать FirstOrDefault<T> / SingleOrDefault<T>, который вернул бы null для любого ссылочного типа T, если строки не были возвращены - person Marc Gravell; 15.04.2020
comment
@MarcGravell, хорошо. Если из хранимой процедуры SQL не возвращаются строки, я не хочу инициализировать переменную List‹T›. Я хочу оставить его нулевым. Может ли ExecuteReader помочь в этом? Как мы делаем проверку HasRows в ADO.NET SQLDataReader? Спасибо. - person Priya; 15.04.2020
comment
@Прия, но почему? этот дополнительный объект не будет иметь значения в контексте запроса ADO.NET, поэтому, если вы хотите уменьшить выделение: это вряд ли будет иметь какое-либо серьезное значение; технически я предполагаю, что Dapper мог вернуть Array.Empty<T>(), но сегодня это не так, IIRC - person Marc Gravell; 15.04.2020
comment
@MarcGravell, да, я действительно хотел сделать это, чтобы уменьшить ненужные выделения. Также мне нужно построить некоторую логику, если база данных возвращает пустой результат. - person Priya; 15.04.2020
comment
@Priya Я думаю, что ты оптимизируешь здесь преждевременно; честно говоря, я не думаю, что это ваше узкое место - person Marc Gravell; 15.04.2020
comment
@MarcGravell, да, я думаю, ты прав. Сейчас я буду использовать Query‹T›. Проверит разницу между нулевым списком и списком с размером 0 с точки зрения выделения памяти. Спасибо за помощь. :) - person Priya; 15.04.2020

Вы можете установить свойства по умолчанию.

Например:

public class BaseEntity
{
    public BaseEntity()
    {
        if (GetType().IsSubclassOf(typeof(BaseEntity)))
        {
            var properties = GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);

            foreach (var property in properties)
            {
                // Get only string properties
                if (property.PropertyType != typeof (string))
                {
                    continue;
                }

                if (!property.CanWrite || !property.CanRead)
                {
                    continue;
                }

                if (property.GetGetMethod(false) == null)
                {
                    continue;
                }
                if (property.GetSetMethod(false) == null)
                {
                    continue;
                }

                if (string.IsNullOrEmpty((string) property.GetValue(this, null)))
                {
                    property.SetValue(this, string.Empty, null);
                }
            }
        }
    }
}

public class CaseOfficer : BaseEntity
{
    public string Title { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public string Telephone { get; set; }
}

Теперь у CaseOfficer появились автосвойства

person Igor Semin    schedule 04.06.2014