Linq SELECT with ExecuteQuery

大憨熊 提交于 2021-01-27 04:53:48

问题


I get the error:

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

With the code:

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

I know this is wrong, but can someone show me how to do it correctly without needing to create a new object preferably?


回答1:


Result of this query is not int[] but one row with numbers.

not good solution: use for every number:

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

or Create sql query

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

or Create class ...




回答2:


I think I have misunderstood the question a little bit. But as @goric explained: An ORM mapper wants to map the results to an object. If you don't want an object or class than don't use an ORM mapper, but use the basic 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];
}



回答3:


The ORM, after retrieving the SQL results, tries to create a new instance of the type you specified, and then find properties on that type with the same name as the columns selected in the query. So in your case, it is trying to create a new int[] and then set properties on it called UserId, IPId, and GameId.

There are a few issues here. First, when creating the instance, by default a parameterless constructor is used. int[] doesn't have one that can be called, and this is the error you are seeing. Assuming it did have one, I expect this code would fail after instantiating it when trying to set a property called UserId.

An easy way around this is to create your own class, as others have answered. If you want a way that doesn't need a new type, you could use something like the non-generic Query class from the dapper library (see Marc Gravell's answer in this post). The Entity Framework also seems to provide some similar functionality using the ObjectQuery and DbDataRecord classes, as shown here.




回答4:


Here is and ugly hack for doing this:

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

Works on my machine...




回答5:


Not answering your question directly, but take care of security...

Your code is probably vulnerable to SQL injection attacks, depending on where comes the value for gamePlayRecordID.

To fix, make the SQL query parameterized (or thoroughly validate the input, if comes from "untrusted" sources):

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

as the first solution showed... Many of the solutions provided might have the very same security problem.




回答6:


It should be something like this

  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;

Code reference taken from http://msdn.microsoft.com/en-us/library/bb361109.aspx




回答7:


I don't think there is a correct way to do it, because it wants to map it to an object with named properties. Even if you are able to instantiate the array, it will fail trying to map it to the named fields.

If you don't want to create a class for it, but are more interested in creating a dynamic object, you can take a look at dapper orm. Install it via nuget. you can do something like this:

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


来源:https://stackoverflow.com/questions/17614545/linq-select-with-executequery

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!