Linq使用ExecuteQuery进行SELECT查询

6

我遇到了以下错误:

在映射期间,类型“System.Int32[]”必须声明一个默认(无参)构造函数。

这是代码:

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];

我知道这样做是错误的,但是否有人可以向我展示如何正确地执行它而不需要创建一个新对象呢?


猜测一下 - 你尝试过使用 List<int> 了吗? - Andrei
我必须问一下,你不想使用class的原因是什么? - Mike Perrenoud
请参考以下网址:http://msdn.microsoft.com/zh-cn/library/vstudio/bb738512%28v=vs.100%29.aspx#_ESQL - Brij
@WebWorld,DbDataRecord也是一个object。它有一个索引器,但它不是一个数组。 - Mike Perrenoud
7个回答

9

这个查询的结果不是 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 只需要把数据放入一个类中。 - Mike Perrenoud

2

我觉得我有点误解这个问题。但是正如@goric所解释的那样:ORM映射器想要将结果映射到一个对象上。如果你不想要一个对象或类,那么就不要使用ORM映射器,而是使用基本的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];
}

+1 是为了至少提供一个好的解决方法。虽然它没有使用“Query”方法,但它确实为结果提供了一个内存高效的对象数组。 - Mike Perrenoud

1
ORM在检索SQL结果后,尝试创建您指定类型的新实例,然后查找该类型中与查询中选择的列名称相同的属性。因此,在您的情况下,它正在尝试创建一个名为int[]的新实例,然后设置称为UserIdIPIdGameId的属性。
这里有几个问题。首先,在创建实例时,默认使用无参构造函数。int[]没有可以调用的构造函数,这就是您看到的错误。假设它确实有一个构造函数,在实例化后尝试设置称为UserId的属性时,我希望此代码将失败。
一个简单的解决方法是创建自己的类,就像其他人已经回答的那样。如果你想要一种不需要新类型的方法,可以使用非泛型的 Query 类,它来自 dapper 库(请参见 Marc Gravell 在 this 帖子中的回答)。Entity Framework 似乎也提供了一些类似的功能,使用 ObjectQueryDbDataRecord 类,如 here 所示。

实际上,Marc的答案使用了Dapper。当利用Dapper时,它会将值放入POCO中,也不能使用数组。最后,我非常确定OP已经知道您提供的所有信息。显然,OP知道如何使用class来做到这一点,并且他知道需要属性名称匹配,他只是试图找到一种避免创建对象的方法。 - Mike Perrenoud
@MichaelPerrenoud:我尽量不对提问者的理解程度做出假设,从问题中也无法明确他对该主题的熟悉程度。我认为答案并不需要使用数组,我的理解是他只是不想显式地创建一个新类型。我认为答案中没有任何冗长或无关紧要的内容。 - goric
当 OP 说“最好不要创建新对象”时,显然 OP 知道如何通过创建新对象来实现。他的理解已经到了这个程度。他不知道的是如何使用像数组这样的东西来实现,其中不必创建对象的新实例。 - Mike Perrenoud

0

虽然没有直接回答你的问题,但是要注意安全...

根据gamePlayRecordID的值来自哪里,你的代码很可能容易受到SQL注入攻击。

为了修复这个问题,需要将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();

作为第一个解决方案展示的……提供的许多解决方案可能存在相同的安全问题。

0

这里有一个做这件事的丑陋的hack:

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();

在我的电脑上可以运行...


-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/zh-cn/library/bb361109.aspx


OP 知道如何使用类来实现。他明确表示不想这样做。他想使用数组。 - Mike Perrenoud
OP 不想创建新类,但他可以使用已经存在的类作为表格。 - Sandip
不,那没有什么不同。他不想创建一个新对象。 - Mike Perrenoud
不,当然不是,但你可以根据问题的提出方式相对容易地推断出他目前对该主题的理解程度。来吧。 - Mike Perrenoud

-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(); 
}

再次强调,Dapper使用POCO。即使是动态对象也是POCO,只是在运行时构建而已。但OP并不想构建一个对象。 - Mike Perrenoud

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接