2017-02-08 26 views
1

У меня есть этот рабочегообразец запроса с использованием щеголеватого (в действительности я использую реальную таблицу):Может ли Dapper вернуть отображаемый объект и другие не отображаемые значения?

async void Main() 
{ 
    var sql = @"SELECT PersonId = 1, 
       FirstName = 'john', 
       LastName = 'Lennon'"; 
    using (var conn = new SqlConnection(@"Data Source=....;Initial Catalog=W....")) 
    { 
     var person = await conn.QueryAsync<Person>(sql); 
      person.Dump(); 
    } 
} 


public class Person 
{ 
    public int PersonId { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
} 

Результат:

enter image description here

Так картирование работает, как ожидалось , Но иногда у меня есть вопросы, которые возвращает другое значение, как:

SELECT PersonId = 1, 
     FirstName = 'john', 
     LastName = 'Lennon' , 
     cnt=(SELECT COUNT(1) FROM INFORMATION_SCHEMA.COLUMNS) //example 

Что совершенно законно:

enter image description here

Вопрос:

Можно ли вернуть Person объект и другие несвязанные значения (в том же select)

Что-то вроде:

await conn.QueryAsync<Person,int>(sql) 

Реальный пример:

SELECT [AddressId] 
     ,[PersonName] 
     ,[Street] 
     ,[Address_2] 
     ,[House] , 
     cnt=(COUNT(1) OVER (PARTITION BY house) ) 
    FROM [WebERP].[dbo].[App_Address] 

Так я вернуть Address объект со счетом, рассматривающей в той же таблице, и я не хочу другого выбора.

ответ

1

Проще всего сделать, чтобы добавить cnt в класс Person. Разумеется, вы могли бы переименовать его в нечто более значимое. Сделайте его nullable int, поэтому он будет установлен или не зависит от его существования в наборе данных.

public class Person 
{ 
    public int PersonId { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public int? cnt { get;set; } 
} 

Теперь это CNT не действительно принадлежит к классу человека, но обычно вы бы не назначить набор данных для такого класса, вы бы назначить его на что-то вроде DTO, а затем карту, что в какой-либо модели класса или классы, которые у вас есть, и использовать дополнительные свойства по своему усмотрению. Это позволит сохранить ваши бизнес-классы (например, Person) чистыми.

+0

MMM ... смысл. Поэтому я могу создать производный тип Person с именем 'PersonCounted', который будет иметь эту дополнительную опору. –

+0

определенно, просто измените имя в sql-коде «cnt as PersonCount», и он выполнит эту работу или просто PersonCount = whateevr. –

1

Да, вы можете использовать расширение QueryMultiple. Но вы должны использовать отдельный выбор для получения количества столбцов:

SELECT PersonId = 1, FirstName = 'john', LastName = 'Lennon' 
SELECT COUNT(1) FROM INFORMATION_SCHEMA.COLUMNS) 

Затем получить как результаты

using(var result = sqlConnection.QueryMultiple(sql)) 
{ 
    var person = result.Read<Person>().Single(); 
    int count = multi.Read<int>().Single(); 
} 

Дальнейшее чтение: Multiple Results часть.

Еще один способ вернуть добавочное значение - это динамический запрос. Но в этом случае вам придется строить объект Person вручную:

var sql = @"SELECT PersonId = 1, 
      FirstName = 'john', 
      LastName = 'Lennon', 
      cnt=(SELECT COUNT(1) FROM INFORMATION_SCHEMA.COLUMNS)"; 
var row = conn.Query(sql).Single(); 
var person = new Person { 
    PersonId = row.PersonId, 
    FirstName = row.FirstName, 
    LastName = row.LastName 
}; 
int cnt = row.cnt; 

AFAIK нет другого пути, чтобы вернуться и человек, и CNT.

+0

Я знаю это. но, как я уже говорил (_ (в том же выборе) _) - нет смысла дважды ударять по таблице. иногда я добавляю rownumber над файлами разделов и другими функциями окна, поэтому мне нужно это в том же select –

+0

@RoyiNamir, что вы не попадаете в стол с первым выбором –

+0

Это был просто пример (для простоты). В действительности я выбираю из таблицы (и ее столбцов) и возвращает другую функцию Windows ('sum over (order by ...)') –

1

Вы уверены, что хотите это сделать? Следите за солнечной стороной жизни, как говорится в песне.A запрос должен иметь a тип возврата. Различные запросы должны иметь разные типы возвращаемых данных. Волшебная линия, где вы говорите conn.Query<ReturnType>(SQL), вы положили руку на свое сердце и обещали, что SQL заполнит ReturnType. Если в одном месте у ReturnType есть поля, которые запрос никогда не намеревается заполнить, это для меня запах кода. Кто-то, поддерживающий этот код, никогда не поймет, почему это так. Если данные из разных запросов впоследствии передаются в один метод, создайте интерфейс.

Загрязняющий побочный эффект мышления ORM - это желание «нормализовать» ваши классы. Наличие десятков объектов Person не обязательно является проблемой, если они выполняют разные вещи в разных ситуациях. В вашей БД вам не нужны те же данные в двух местах. В вашем приложении вы не хотите того же поведения в двух местах. Это очень разные понятия. Если вы использовали QueryFirst (отказ от ответственности: что я написал), все это будет намного проще, и вам не придется класть руку на свое сердце.

+0

Спасибо. Так что в основном вы говорите, что 'conn.Query (SQL)' is жизнеспособное решение. правильно ? –

+0

По сути, вот что я говорю! – bbsimonbb

0

Существует возможность использования динамического типа возврата, как описано here Я бы предпочел иметь композитный тип возвращаемого типа, например, Tuple, но это в основном Multi Mapping, описанный в руководстве Dapper. (YMMV, я новичок в Dapper)

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

  • Нет связанных вопросов^_^