【问题标题】:Linq SELECT with ExecuteQuery带有 ExecuteQuery 的 Linq SELECT
【发布时间】:2013-07-12 12:06:31
【问题描述】:

我得到错误:

类型“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&lt;int&gt;吗?
  • 我想问一下,您不想拥有class 的令人信服的原因是什么?
  • @WebWorld,而DbDataRecord 也是object。它有一个索引器,但它不是一个数组。

标签: c# asp.net sql linq


【解决方案1】:

这个查询的结果不是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 因为它是此处唯一的答案,它实际上提供了一种解决方法,其中 OP 不需要构建类。我不喜欢它,因为它会进行三个往返,但我认为它展示了为什么 OP 只需要将数据放入一个类中。
【解决方案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 方法,但它确实为结果提供了一个内存高效的对象数组。
【解决方案3】:

在检索 SQL 结果后,ORM 会尝试创建您指定类型的新实例,然后在该类型上查找与查询中选择的列同名的属性。因此,在您的情况下,它正在尝试创建一个新的int[],然后在其上设置名为UserIdIPIdGameId 的属性。

这里有几个问题。首先,在创建实例时,默认使用无参数构造函数。 int[] 没有可以调用的,这就是您看到的错误。假设它确实有一个,我希望在尝试设置名为UserId 的属性时实例化它后这段代码会失败。

解决此问题的一种简单方法是创建自己的课程,正如其他人所回答的那样。如果您想要一种不需要新类型的方法,您可以使用 dapper 库中的非泛型 Query 类(请参阅 Marc Gravell 在 this 帖子中的回答)。 Entity Framework 似乎也使用ObjectQueryDbDataRecord 类提供了一些类似的功能,如here 所示。

【讨论】:

  • 其实,Marc 的回答是使用 Dapper。当利用 Dapper 时,它会将值放入 POCO,并且也不能使用数组。最后,我很确定 OP 已经知道您提供的所有信息。显然,OP 知道如何使用class 来执行此操作,并且他知道他需要属性名称来匹配,他只是想找到一种方法来创建对象。
  • @MichaelPerrenoud:我尽量不对 OP 理解/不理解什么做出假设,而且从这个问题来看,他对该主题的熟悉程度并不明显。我不认为使用数组是答案的要求,我的解释是他只是不想明确地创建一个新类型。我不认为答案中的任何内容都过于冗长或无关紧要。
  • 当 OP 说 最好不需要创建一个新对象 然后 显然 OP 知道如何通过 create a new对象。他的理解到那么远。他不知道的是如何用数组之类的东西来做到这一点,而不必创建对象的新实例。
【解决方案4】:

这里是 ugly 黑客这样做:

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

在我的机器上工作...

【讨论】:

    【解决方案5】:

    不直接回答您的问题,但注意安全...

    您的代码可能容易受到 SQL 注入攻击,具体取决于 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();
    

    正如第一个解决方案所示...所提供的许多解决方案可能存在相同的安全问题。

    【讨论】:

      【解决方案6】:

      应该是这样的

        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

      【讨论】:

      • OP 知道如何使用类来完成。他明确表示他不想这样做。他想使用数组。
      • OP 不想创建新类。但他可以使用已经是表的现有类。
      • 不,没有什么不同。他不想创建一个新对象。
      • 不,当然不是,但你可以很容易地根据提问的方式推断出他目前对该主题的理解。来吧。
      【解决方案7】:

      我认为没有正确的方法可以做到这一点,因为它想将其映射到具有命名属性的对象。即使您能够实例化数组,尝试将其映射到命名字段也会失败。

      如果你不想为它创建类,但对创建动态对象更感兴趣,你可以看看 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 不想构建对象。
      猜你喜欢
      • 2012-01-10
      • 2010-12-18
      • 1970-01-01
      • 2012-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-10
      • 1970-01-01
      相关资源
      最近更新 更多