2013-07-12 4 views
3

я получаю ошибку:Linq ВЫБРАТЬ с ExecuteQuery

The type 'System.Int32[]' must declare a default (parameterless) constructor in order to be constructed during mapping.

С кодом:

var gamePlayRecord = db.ExecuteQuery<int[]>("SELECT UserID, IPID, GameID FROM ArcadeGames WHERE ID = " + gamePlayRecordID).Single(); 
var userID = gamePlayRecord[0]; 
var ipID = gamePlayRecord[1]; 
var gameID = gamePlayRecord[2]; 

Я знаю, что это неправильно, но может кто-то показать мне, как это сделать правильно, без необходимости создания предпочтительным является новый объект?

+0

Просто дикая догадка - вы пробовали «Список '? – Andrei

+0

Я должен спросить, какова веская причина, по которой вы не хотите иметь «класс»? –

+0

ссылаются на http://msdn.microsoft.com/en-us/library/vstudio/bb738512%28v=vs.100%29.aspx#_ESQL – Brij

ответ

-1

Это должно быть что-то вроде этого

var gamePlayRecord = db.ExecuteQuery<ArcadeGames>(@"SELECT UserID, IPID, GameID FROM ArcadeGames WHERE ID = {0}", gamePlayRecordID).Single(); 

       var userID = gamePlayRecord.UserID; 
       var ipID = gamePlayRecord.IPID; 
       var gameID = gamePlayRecord.GameID; 

Код ссылки взяты из http://msdn.microsoft.com/en-us/library/bb361109.aspx

+0

OP знает, как это сделать с классом. Он специально заявил, что не хочет этого делать. Он хотел использовать массив. –

+0

OP не хочет создавать новый класс. но он может использовать существующий класс, который уже является таблицей. – Bhaarat

+0

Нет, это ничем не отличается. Он не хочет ** создавать новый объект. ** –

1

ОРМ, после получения результатов SQL, пытается создать новый экземпляр указанного типа, а затем найти свойства этого типа с тем же именем, что и столбцы, выбранные в запросе. Таким образом, в вашем случае он пытается создать новый int[], а затем установить для него свойства под названием UserId, IPId и GameId.

Здесь есть несколько вопросов. Во-первых, при создании экземпляра по умолчанию используется конструктор без параметров. int[] не может быть вызван, и это ошибка, которую вы видите. Предполагая, что у него есть один, я ожидаю, что этот код завершится неудачно после его создания при попытке установить свойство с именем UserId.

Простой способ создать свой собственный класс, как и другие. Если вам нужен способ, который не нуждается в новом типе, вы можете использовать что-то вроде не общего класса Query из библиотеки dapper (см. Ответ Марка Гравелла в сообщении this). Как представляется, структура Entity Framework также предоставляет некоторые аналогичные функции, используя классы ObjectQuery и DbDataRecord, как показано на рисунке here.

+0

Собственно, ответ Марка использует Dapper. При использовании Dapper он помещает значения в POCO и не может использовать массив. Наконец, я уверен, что ОП уже знает всю предоставленную вами информацию. Очевидно, что ОП знает, как это сделать с помощью класса, и он знает, что ему нужны имена свойств, которые соответствуют друг другу, он просто пытается найти способ создания объекта. –

+0

@MichaelPerrenoud: Я стараюсь не делать предположений о том, что OP не понято/не понято, и от вопроса не ясно, каков его уровень родства с субъектом. Я не вижу использования массива, являющегося требованием к ответу, моя интерпретация заключалась в том, что он просто не хотел явно создавать новый тип. Я не думаю, что что-либо в ответе слишком затянуто или не имеет значения. – goric

+0

Когда OP говорит ** без необходимости создания нового объекта, предпочтительно **, а затем ** четко ** ОП знает, как это сделать путем * создания нового объекта. * Его понимание идет так далеко. То, что он ** не знает **, - это * как сделать это с чем-то вроде массива, где не нужно создавать новый экземпляр объекта. * –

7

Результат этого запроса не int[], а одна строка с номерами.

не

хорошее решение: использовать для каждого номера:

int userID = db.ExecuteQuery<int>("SELECT UserID FROM ArcadeGames WHERE ID = " + gamePlayRecordID).Single(); 
int ipID = db.ExecuteQuery<int>("SELECT IPID FROM ArcadeGames WHERE ID = " + gamePlayRecordID).Single(); 
int gameID db.ExecuteQuery<int>("SELECT GameID FROM ArcadeGames WHERE ID = " + gamePlayRecordID).Single(); 

или Создать запрос SQL

db.ExecuteQuery<int>(@" 
SELECT UserID FROM ArcadeGames WHERE ID = {0} 
UNION ALL 
SELECT IPID FROM ArcadeGames WHERE ID = {0} 
UNION ALL 
SELECT GameID FROM ArcadeGames WHERE ID = {0}", 
gamePlayRecordID).ToList(); 

или Создать класс ...

+1

+1, так как это единственный ответ здесь ** что фактически обеспечивает работу, в которой OP не нужно будет создавать класс. Мне это не нравится, потому что он совершает три круглых поездки, но я думаю, что это демонстрирует, почему OP просто нужно помещать данные в класс. –

-1

Я не думаю, что это правильно способ сделать это, потому что он хочет сопоставить его с объектом с именованными свойствами. Даже если вы можете создать экземпляр массива, он не попытается сопоставить его с именованными полями.

Если вы не хотите создавать для него класс, но более заинтересованы в создании динамического объекта, вы можете взглянуть на dapper orm. Установите его через nuget. вы можете сделать что-то вроде этого:

using (var sqlConnection 
     = new SqlConnection(connectionString)) 
{ 
    sqlConnection.Open(); 

    IEnumerable products = sqlConnection 
     .Query("Select * from Products where Id = @Id", 
         new {Id = 2}); 

    foreach (dynamic product in products) 
    {   
     ObjectDumper.Write(string.Format("{0}-{1}", product.Id, product.ProductName)); 
    } 
    sqlConnection.Close(); 
} 
+0

Опять же, Dapper использует POCO. Даже динамическим объектом является POCO. Он просто построен во время выполнения. OP * не хочет строить объект. * –

2

Я думаю, что я понял вопрос немного. Но как пояснил @goric: ORM-карппер хочет сопоставить результаты с объектом. Если вы не хотите, чтобы объект или класс не использовали ORM mapper, но используйте базовый SqlDataReader.

SqlCommand command = new SqlCommand("SELECT UserID, IPID, GameID FROM ArcadeGames WHERE ID = " + gamePlayRecordID, connection); 
SqlDataReader reader = command.ExecuteReader(); 
if (reader.Read()) 
{ 
    var userID = reader[0]; 
    var ipID = reader[1]; 
    var gameID = reader[2]; 
} 
+0

+1 для обеспечения хотя бы хорошего обходного пути. Хотя он не использует метод «Query», он предоставляет массив объектов с эффективностью памяти для результатов. –

0

Вот и некрасиво хак для этого:

var gamePlayRecord = db.ExecuteQuery<string>(
     "SELECT cast(UserID as nvarchar(10)) + ';' + cast(IPID as nvarchar(10)) + ';' + cast(GameID as nvarchar(10)) as a FROM ArcadeGames WHERE ID = " + gamePlayRecordID 
    ) 
    .Single() 
    .Split(';') 
    .Select(i => int.Parse(i)) 
    .ToArray(); 

Работает на моей машине ...

0

Не отвечая на ваш вопрос прямо, но заботиться о безопасности ...

Ваш код: Возможно, уязвим для атак SQL-инъекций, в зависимости от того, где находится va lue для gamePlayRecordID.

Чтобы исправить, сделать SQL запрос параметрироваться (или тщательно проверить правильность ввода, если происходит от «ненадежных» источников):

db.ExecuteQuery<int>(@" 
    SELECT UserID FROM ArcadeGames WHERE ID = {0} 
    UNION ALL 
    SELECT IPID FROM ArcadeGames WHERE ID = {0} 
    UNION ALL 
    SELECT GameID FROM ArcadeGames WHERE ID = {0}", 
    gamePlayRecordID).ToList(); 

как первое решение показавших ... Многие из решений, предусмотренных может иметь та же проблема безопасности.