NullPointerException while Querying for mapped CustomObject - c#

I have following code:
ActiveModule resultObject = null;
StringBuilder sqlStringBuilder = new StringBuilder();
sqlStringBuilder.AppendLine("SELECT * FROM suite_activemodule as _module");
sqlStringBuilder.AppendLine("WHERE CityID = #CityID AND BaseModuleID = #BaseModuleID");
using (MySqlConnection connection = new MySqlConnection(ConnectionString))
{
var _resultList = connection.Query<ActiveModule>(sqlStringBuilder.ToString(), new { CityID = cityID, ModuleID = moduleID }, null, true, null, null); //<- This is were I get the error...
int listSize = _resultList.Count();
if (_resultList != null && !_resultList.Count().Equals(0))
{
resultObject = _resultList.ToList().First();
resultObject.Module = BaseModuleRepository.GetByID(resultObject.ModuleID);
}
}
The query itself works fine but as soon as I try to run the query I get the following error message:
bei MySql.Data.MySqlClient.MySqlConnection.get_ServerThread()
bei MySql.Data.MySqlClient.MySqlConnection.Abort()
bei MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior
behavior)
bei Dapper.SqlMapper.ExecuteReaderWithFlagsFallback(IDbCommand cmd,
Boolean wasClosed, CommandBehavior behavior) in
C:\projects\dapper\Dapper\SqlMapper.cs:Zeile 1053.
bei Dapper.SqlMapper.d__138`1.MoveNext() in
C:\projects\dapper\Dapper\SqlMapper.cs:Zeile 1081.
bei System.Collections.Generic.List1..ctor(IEnumerable1 collection)
bei System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
bei Dapper.SqlMapper.Query[T](IDbConnection cnn, String sql, Object
param, IDbTransaction transaction, Boolean buffered, Nullable1
commandTimeout, Nullable1 commandType) in
C:\projects\dapper\Dapper\SqlMapper.cs:Zeile 723.
...Repository.GetByCityIDAndModuleID(Int64 cityID, Int64 moduleID)
...DeactivateModule(String moduleID)
But I am running multiple queries like this kind before and dont get this error. It don't make that much sense because nothing of the used stuff is really null.
I have already did a clean build and also a full rebuild via Visual Studio.
Does anyone know about this issue and know how to fix it?

As mentioned in the comments, the NullReferenceException can be fixed by assigning the 'BaseModuleID' in your call to Query<>() like this:
var _resultList = connection.Query<ActiveModule>(sqlStringBuilder.ToString(), new { CityID = cityID, BaseModuleID = moduleID }, null, true, null, null);
Another suggestion: you are calling _resultList.Count() twice. If your query returns a large # of results, this could be expensive. Since you are only processing the first item in the list, you could use FirstOrDefault() on the list instead of Count(). Or, even better, you could use QueryFirstOrDefault<>() on the MySqlConnection like this:
ActiveModule resultObject = null;
StringBuilder sqlStringBuilder = new StringBuilder();
sqlStringBuilder.AppendLine("SELECT * FROM suite_activemodule as _module");
sqlStringBuilder.AppendLine("WHERE CityID = #CityID AND BaseModuleID = #BaseModuleID");
using (MySqlConnection connection = new MySqlConnection(ConnectionString))
{
resultObject = connection.QueryFirstOrDefault<ActiveModule>(sqlStringBuilder.ToString(), new { CityID = cityID, BaseModuleID = moduleID });
if (resultObject != null)
{
resultObject.Module = BaseModuleRepository.GetByID(resultObject.ModuleID);
}
}
Good luck!

Related

How to mock method properly to return specific data when checking other method with Autofac.Moq?

Have such C# code and try to check method IsFailureProcessStatus to return true.
Query method from dapper class SqlMapper which call stored procedures with parameters.
public class DatabaseManager : IDatabaseManager
{
private readonly SqlConnection CoreDbProcessesConnection;
private readonly SqlConnection HrReportDbConnection;
// there are other private fields with parameters and sql-procedures names
public DatabaseManager(IDbConnectionsProvider dbConnectionsProvider)
{
this.CoreDbProcessesConnection = dbConnectionsProvider.CoreDbProcessesConnection;
this.HrReportDbConnection = dbConnectionsProvider.HrReportDbConnection;
}
public List<CoreProcessStatusDto> GetProcessStatusIds(string ProcessName, DateTime dateTime)
{
var parameters = new DynamicParameters();
parameters.Add(processStatusProcedureParamName01, ProcessName);
parameters.Add(processStatusProcedureParamName02, dateTime);
var output = this.CoreDbProcessesConnection
.Query<CoreProcessStatusDto>(ProcessStatusProcedureName, parameters, commandType: CommandType.StoredProcedure).ToList();
return output;
}
public bool IsFailureProcessStatus(StepDto.StepDescription step, DateTime dateTime)
{
bool isStepFailure = true;
Stopwatch doStepUntil = new Stopwatch();
doStepUntil.Start();
while (doStepUntil.Elapsed < TimeSpan.FromSeconds(step.SecondsElapsed))
{
step.StatusTypesList = this.GetProcessStatusIds(step.ProcessName, dateTime);
var statusTypesStepSelection = step.StatusTypesList.Select(st => st.ProcessStatusTypeId).ToList();
//...
// if...else operations here to make step true or false
//...
}
doStepUntil.Stop();
return isStepFailure;
}
}
Unit test code is located below:
[TestClass]
public class DatabaseManagerTests
{
[TestMethod]
public void IsFailureProcessStatus_ReturnTrue()
{
DateTime dateTime = DateTime.Now;
StepDto step1Dto = new StepDto()
{
JobName = "ETL - HR - FilesImport - Reporting",
JobStepName = "RunMCP_User_Department_Map",
Step = new StepDto.StepDescription()
{
StatusTypesList = new List<CoreProcessStatusDto>(),
ProcessName = "HR_User_Department_Map_Import",
SecondsElapsed = 30,
PackageCount = 2
}
};
using (var mock = AutoMock.GetLoose())
{
var dbProviderMock = new Mock<IDbConnectionsProvider>(MockBehavior.Loose);
var dbMock = new Mock<DatabaseManager>(dbProviderMock.Object);
mock.Mock<IDatabaseManager>()
.Setup(p => p.GetProcessStatusIds(step1Dto.Step.ProcessName, dateTime))
.Returns(GetCoreProcessesStatusIdsTest());
var sut = mock.Provide(dbMock.Object);
//var sut = mock.Create<DatabaseManager>();
var actual = sut.IsFailureProcessStatus(step1Dto.Step, dateTime);
Assert.IsTrue(actual);
}
}
private List<CoreProcessStatusDto> GetCoreProcessesStatusIdsTest()
{
var output = new List<CoreProcessStatusDto>()
{
new CoreProcessStatusDto() { ProcessStatusTypeId = 3 },
new CoreProcessStatusDto() { ProcessStatusTypeId = 2 }
};
return output;
}
}
I tried to setup GetProcessStatusIds method to return values when calling sut.IsFailureProcessStatus code, but while debug its run GetProcessStatusIds and throw NullReferenceException exception when try calling Query method.
Test Name: IsFailureProcessStatus_ReturnTrue
Test Outcome: Failed
Result StackTrace:
at Dapper.SqlMapper.<QueryImpl>d__140`1.MoveNext() in C:\projects\dapper\Dapper\SqlMapper.cs:line 1066
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at Dapper.SqlMapper.Query[T](IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Boolean buffered, Nullable`1 commandTimeout, Nullable`1 commandType) in C:\projects\dapper\Dapper\SqlMapper.cs:line 721
at ATP.HR.FolderWatcher.Service.Managers.DatabaseManager.GetProcessStatusIds(String ProcessName, DateTime dateTime) in C:\HOME\anatolii.dmitryv\src\HRM\hr-folder-watcher-service\ATP.HR.FolderWatcher.Service\Managers\DatabaseManager.cs:line 46
at ATP.HR.FolderWatcher.Service.Managers.DatabaseManager.IsFailureProcessStatus(StepDescription step, DateTime dateTime) in C:\HOME\anatolii.dmitryv\src\HRM\hr-folder-watcher-service\ATP.HR.FolderWatcher.Service\Managers\DatabaseManager.cs:line 83
at ATP.HR.FolderWatcher.Service.Test.DatabaseManagerTests.IsFailureProcessStatus_ReturnTrue() in C:\HOME\anatolii.dmitryv\src\HRM\hr-folder-watcher-service\ATP.HR.FolderWatcher.Service.Tests\DatabaseManagerTests.cs:line 57
Result Message:
Test method ATP.HR.FolderWatcher.Service.Test.DatabaseManagerTests.IsFailureProcessStatus_ReturnTrue threw exception:
System.NullReferenceException: Object reference not set to an instance of an object.
And what exactly I do wrong in mock of this method? How I can say to test do not run this GetProcessStatusIds and just return hardcoded values?
tried this using but it didnt work for me:
using (var mock = AutoMock.GetLoose())
{
mock.Mock<IDatabaseManager>()
.Setup(p => p.GetProcessStatusIds(It.IsAny<string>(), It.IsAny<DateTime>()))
.Returns(GetCoreProcessesStatusIdsTest());
var sut = mock.Create<DatabaseManager>();
var actual = sut.IsFailureProcessStatus(step1Dto.Step, dateTime);
Assert.IsTrue(actual);
}
The first thing when doing unit testing is to define the goal of the test, in your question you are trying to test the inside logic of IsFailureProcessStatus, the problem here is that you mocking the interface IDatabaseManager that has the IsFailureProcessStatus method.
You don't need that mocking, you will only will need to mock IDatabaseManager when it uses as supplier for other clients services.
And because you are testing the inside logic of IsFailureProcessStatus you will only need to mock and setup method that are needed for the execution of the inside logic like IDbConnectionsProvider and setup its method of CoreDbProcessesConnection for it to be available to the DatabaseManager real instance.
var dbProviderMock = new Mock<IDbConnectionsProvider>(MockBehavior.Loose);
dbProviderMock
.Setup(p => p.CoreDbProcessesConnection)
.Returns(new SqlConnection(...));
DatabaseManager databaseManager = new DatabaseManager(dbProviderMock.Object);
var actual = databaseManager.IsFailureProcessStatus(step1Dto.Step, dateTime);
Assert.IsTrue(actual);
I can understand why you wrongly tried to mock GetProcessStatusIds, but it won't needed since we have the real instance of DatabaseManager, so you will only be mocking depended interfaces that are needed in the execution process of GetProcessStatusIds, thats why we does not need here the setup of HrReportDbConnection.

Getting MultiExec is not supported by ExecuteReader when running an SPR

I wrote the following method
public async Task<DataTable> ExecuteProcedureToDataTableAsync(string spName, object parameters, int? commandTimeout = null, bool userPrefix = false)
{
using (var connection = new SqlConnection(_ConnectionString))
{
string spNameWithPrefix = GetSpNameWithPrefix(spName, userPrefix);
var dt = new DataTable();
_Logger.Debug($"Executing Query: [{spNameWithPrefix}], with params:[{parameters.ToJsonString()}]");
dt.Load(await connection.ExecuteReaderAsync(spNameWithPrefix, parameters, commandTimeout: commandTimeout, commandType: CommandType.StoredProcedure));
_Logger.Debug($"Completed Query To DataTable: [{spNameWithPrefix}], result columnCount:[{dt.Columns.Count}], result row count:[{dt.Rows.Count}]");
return dt;
}
}
and invoke it like so:
using (var results = await ExecuteProcedureToDataTableAsync(StoredProcedureFullName, StoredProcedureParams, Timeout, userPrefix: false))
{
ExportReport(requestModel, results);
}
and I get the exception:
MultiExec is not supported by ExecuteReader
is it not supported to executeReader with spr ?
Multiple executions aren't supported by ExecuteReader. Use QueryMultiple instead.

SqlDataReader Throws "Invalid attempt to read when no data is present" but OleDbReader does not

I migrated an Access database to SQL using Microsoft SQL Server Migration Assistant.
Now, I am having trouble reading data.
return reader.GetInt32(0); Throws Invalid attempt to read when no data is present exception after 32 rows retrieved. If I add CommandBehavior.SequentialAccess to my command, I am able to read 265 rows, every time.
The data
The query (in SQL Management Studio):
SELECT *
FROM Products2
WHERE Products2.PgId = 337;
There is nothing special about row 32, and if I reverse the order, it is still row 32 that kills it.
Row 265, just for good measure.
The code
The query:
SELECT *
FROM Products2
WHERE Products2.PgId = #productGroupId;
The parameter:
Name = "productGroupId"
Value = 337
The execution:
public async Task ExecuteAsync(string query, Action<IDataReader> onExecute, params DataParameter[] parameters)
{
using(var command = builder.BuildCommand(query))
{
foreach(var parameter in parameters)
command.AddParameter(parameter);
if(!connection.IsOpen)
connection.Open();
await Task.Run(async () =>
{
using(var reader = await command.ExecuteAsync())
if(await reader.ReadAsync())
onExecute(reader);
});
}
}
And reading:
await executor.ExecuteAsync(query, async reader =>
{
do
{
products.Add(GetProduct(reader));
columnValues.Enqueue(GetColumnValues(reader).ToList());
} while(await reader.ReadAsync());
}, parameters.ToArray());
await reader.ReadAsync() returns true, but when GetProduct(reader) calls reader.GetInt32(0); for the 32nd time, it throws the exception.
It works fine if the data is less than 32 rows, or 265 in case of SequentialAccess.
I tried increasing the CommandTimeout, but it didn't help. When I swap the connection to OleDb again, it works just fine.
Thanks in advance.
EDIT
If I replace * in the query with just a few specific columns, it works. When I read ~12 columns, it fails, but later than row 32.
As per request, GetProduct:
private Product GetProduct(IDataReader productReader)
{
return new Product
{
Id = productReader.ReadLong(0),
Number = productReader.ReadString(2),
EanNo = productReader.ReadString(3),
Frequency = productReader.ReadInt(4),
Status = productReader.ReadInt(5),
NameId = productReader.ReadLong(6),
KMPI = productReader.ReadByte(7),
OEM = productReader.ReadString(8),
CurvesetId = productReader.ReadInt(9),
HasServiceInfo = Convert.ToBoolean(productReader.ReadByte(10)),
ColumnData = new List<ColumnData>()
};
}
GetColumnData:
private IEnumerable<long> GetColumnValues(IDataReader productReader)
{
var columnValues = new List<long>();
int columnIndex = 11;
while(!productReader.IsNull(columnIndex))
columnValues.Add(productReader.ReadLong(columnIndex++));
return columnValues;
}
And the adapter:
public long ReadLong(int columnIndex)
{
return reader.GetInt32(columnIndex);
}
Alright, it is getting long. :)
Thanks to #Igor, I tried creating a small working example. This seem to work fine:
private static async Task Run()
{
var result = new List<Product>();
string conString = #" ... ";
var con = new SqlConnection(conString);
con.Open();
using(var command = new SqlCommand("SELECT * FROM Products2 WHERE Products2.PgId = #p;", con))
{
command.Parameters.Add(new SqlParameter("p", 337));
await Task.Run(async () =>
{
using(var productReader = await command.ExecuteReaderAsync())
while(await productReader.ReadAsync())
{
result.Add(new Product
{
Id = productReader.GetInt32(0),
Number = productReader.GetString(2),
EanNo = productReader.GetString(3),
Frequency = productReader.GetInt16(4),
Status = productReader.GetInt16(5),
NameId = productReader.GetInt32(6),
KMPI = productReader.GetByte(7),
OEM = productReader.GetString(8),
CurvesetId = productReader.GetInt16(9),
HasServiceInfo = Convert.ToBoolean(productReader.GetByte(10))
});
GetColumnValues(productReader);
}
});
}
Console.WriteLine("End");
}
private static IEnumerable<long> GetColumnValues(SqlDataReader productReader)
{
var columnValues = new List<long>();
int columnIndex = 11;
while(!productReader.IsDBNull(columnIndex))
columnValues.Add(productReader.GetInt32(columnIndex++));
return columnValues;
}
}
Here's the data in Access, just in case:
I managed to fix the problem.
I still have questions though, since I don't understand why this didn't affect Access.
I changed:
public async Task ExecuteAsync(string query, Action<IDataReader> onExecute, params DataParameter[] parameters)
{
using(var command = builder.BuildCommand(query))
{
foreach(var parameter in parameters)
command.AddParameter(parameter);
if(!connection.IsOpen)
connection.Open();
await Task.Run(async () =>
{
using(var reader = await command.ExecuteAsync())
if(await reader.ReadAsync())
onExecute(reader);
});
}
}
To:
public async Task ExecuteAsync(string query, Func<IDataReader, Task> onExecute, params DataParameter[] parameters)
{
using(var command = builder.BuildCommand(query))
{
foreach(var parameter in parameters)
command.AddParameter(parameter);
if(!connection.IsOpen)
connection.Open();
using(var reader = await command.ExecuteAsync())
await onExecute(reader);
}
}
If someone can explain why this helped, I would really appreciate it.

EF6 Retrying procedure throws "The SqlParameter is already contained by another SqlParameterCollection" for SqlQuery command

I'm trying to use the DBExecutionStrategy to retry queries that have timed out, but when the time out happens I get the error "The SqlParameter is already contained by another SqlParameterCollection". I'm using EF6.
My Query:
using (var ctx = new EntityModel())
{
IEnumerable<ItemResponse> items= ctx.Database.SqlQuery<ItemResponse>(
"spItemListGet #UserID", new SqlParameter("#UserID", UserID)
).ToList();
}
My Execution Strategy:
protected override bool ShouldRetryOn(Exception ex)
{
bool retry = false;
SqlException sqlException = ex as SqlException;
if (sqlException != null)
{
int[] errorsToRetry =
{
-2, //Timeout
};
if (sqlException.Errors.Cast<SqlError>().Any(x => errorsToRetry.Contains(x.Number)))
{
retry = true;
}
else
{
throw ex; //dont retry
}
}
return retry;
}
The stack trace:
System.ArgumentException: The SqlParameter is already contained by another SqlParameterCollection.
at System.Data.SqlClient.SqlParameterCollection.Validate(Int32 index, Object value)
at System.Data.SqlClient.SqlParameterCollection.AddRange(Array values)
at System.Data.Entity.Core.Objects.ObjectContext.CreateStoreCommand(String commandText, Object[] parameters)
at System.Data.Entity.Core.Objects.ObjectContext.ExecuteStoreQueryInternal[TElement](String commandText, String entitySetName, ExecutionOptions executionOptions, Object[] parameters)
at System.Data.Entity.Core.Objects.ObjectContext.<>c__DisplayClass65`1.<ExecuteStoreQueryReliably>b__64()
at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
at System.Data.Entity.Core.Objects.ObjectContext.<>c__DisplayClass65`1.<ExecuteStoreQueryReliably>b__63()
at System.Data.Entity.Infrastructure.DbExecutionStrategy.Execute[TResult](Func`1 operation)
at System.Data.Entity.Core.Objects.ObjectContext.ExecuteStoreQueryReliably[TElement](String commandText, String entitySetName, ExecutionOptions executionOptions, Object[] parameters)
at System.Data.Entity.Core.Objects.ObjectContext.ExecuteStoreQuery[TElement](String commandText, ExecutionOptions executionOptions, Object[] parameters)
at System.Data.Entity.Internal.InternalContext.<>c__DisplayClass14`1.<ExecuteSqlQuery>b__13()
at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
What could it be done to prevent this error? Can Database.SqlQuery be used for with the execution strategy?
The short answer: No, you can't do this (if your command has parameters).
The long answer:
Here is a minimal repro of the issue. I stripped out the execution strategy from the picture, and faked it with a loop instead. This logic is implemented in the ObjectContext, specifically in the ExecuteStoreQueryInternalAsync method. The problem seems to be that a command.Parameters.Clear() call is missing from the cleanup part.
static void Main(string[] args)
{
TestQuery();
}
private static void TestQuery()
{
using (var ctx = new ProductContext())
{
var parameter = new SqlParameter("#ID", 1);
var commandText = "select * from product where ProductId = #ID";
Action a = () =>
{
IDbCommand command = new SqlCommand();
command.CommandText = commandText;
command.Parameters.Add(parameter);
command.Connection = ctx.Database.Connection;
if (command.Connection.State != ConnectionState.Open)
{
command.Connection.Open();
}
var reader = command.ExecuteReader();
try
{
throw new Exception();
while (reader.Read())
{
var pId = reader["ProductID"];
}
reader.Close();
}
catch (Exception exc)
{
//for simplification, we just swallow this error, but in reality the connection error
//would reach the IDbExecutionStrategy, and would do a retry. Instead we fake the retry
//with a loop below
}
finally
{
reader.Dispose();
//command.Parameters.Clear(); <--------- THIS LINE IS MISSING FROM EF
command.Dispose();
}
};
for (int i = 0; i < 2; i++) // we fake the retry with a loop now
{
a();
}
}
}

SqlCeDataReader is always null

Hey Guys I'm working on Windows Mobile 5.0 (.Net 2.0)
and I'm stuck at a small problem where my reader is always being null. My connection is fine and I believe everything else is fine the only problem is with the reader.
In my exception catch it says
((System.Data.SqlServerCe.SqlCeException)(e)) : {"The operation completed successfully."}
InnerException: Could not evaluate expression
My database file is not corrupt I opened it outside the application and everything looks fine.
My code is as follows:
public static List<Image> GetAll(BOI caller)
{
List<Image> images = new List<Image>();
SqlCeConnection c = Connection.GetConnection(caller.ConnectionString);
if (c != null)
{
SqlCeCommand command = new SqlCeCommand("SELECT * FROM Images", c);
SqlCeDataReader reader = null;
try
{
reader = command.ExecuteReader(); <<<<< reader is null <<<<<<<
}
catch (Exception e)
{
while (reader != null && reader.Read())
{
Image temp = new Image((int)reader["imageKey"],
(String)reader["filename"],
(byte[])reader["image"],
(reader["labelKey"] == DBNull.Value ? null : (int?)reader["labelKey"]),
(int)reader["priority"]);
temp.SetDBName(caller.ConnectionString);
images.Add(temp);
}
}
}
return images;
}
EDIT
I open my connection in Connection.GetConnection(..);
EDIT:2
The e.StackTrace:
at System.Data.SqlServerCe.SqlCeDataReader.ProcessResults(Int32 hr)
at System.Data.SqlServerCe.SqlCeDataReader.FillMetaData(SqlCeCommand command)
at System.Data.SqlServerCe.SqlCeCommand.InitializeDataReader(SqlCeDataReader reader, Int32 resultType)
at System.Data.SqlServerCe.SqlCeCommand.ExecuteCommand(CommandBehavior behavior, String method, ResultSetOptions options)
at System.Data.SqlServerCe.SqlCeCommand.ExecuteReader(CommandBehavior behavior)
at System.Data.SqlServerCe.SqlCeCommand.ExecuteReader()
at Oralys.BOI.DataAccess.ImageMapper.GetAll(BOI caller)
at Oralys.BOI.BOI.get_Images()
at Oralys.BOI.BOI_Controller.FetchAllImages()
at IdeoVoiceMobile.RunProfile.InitBOI()
at IdeoVoiceMobile.RunProfile..ctor()
at IdeoVoiceMobile.Program.startProfile()
at IdeoVoiceMobile.Program.Main()
Get Connection function:
public static SqlCeConnection GetConnection(string connectionString)
{
SqlCeConnection conn = null;
try
{
if (connections.Count == 0)
{
OpenConnection(connectionString);
}
conn = connections[connectionString];
}
catch (System.Exception)
{
}
return conn;
}
EDIT:3
Exception code when using
SqlCeCommand command = new SqlCeCommand("SELECT * FROM Images Where
imageKey=6", c);
ExceptionCode: 0xc0000005
ExceptionAddress: 0x0115438c
Reading: 0x00000000
Faulting module: sqlceqp35.dll
Offset: 0x0001438c
at NativeMethods.GetKeyInfo(IntPtr pIUnknown, IntPtr pTx, String pwszBaseTable, IntPtr prgDbKeyInfo, Int32 cDbKeyInfo, IntPtr pError)
at SqlCeDataReader.FillMetaData(SqlCeCommand command)
at SqlCeCommand.InitializeDataReader(SqlCeDataReader reader, Int32 resultType)
at SqlCeCommand.ExecuteCommand(CommandBehavior behavior, String method, ResultSetOptions options)
at SqlCeCommand.ExecuteReader(CommandBehavior behavior)
at SqlCeCommand.ExecuteReader()
at ImageMapper.GetAll(BOI caller)
at BOI.get_Images()
at BOI_Controller.FetchAllImages()
at RunProfile.InitBOI()
at RunProfile..ctor()
at Program.startProfile()
at Program.Main()
You'll never hit the following line of code unless cm.executereader throws an exception:
while (reader != null && reader.Read())
Try moving the below code outside of the catch statement
while (reader != null && reader.Read())
{
Image temp = new Image((int)reader["imageKey"],
(String)reader["filename"],
(byte[])reader["image"],
(reader["labelKey"] == DBNull.Value ? null : (int?)reader["labelKey"]),
(int)reader["priority"]);
temp.SetDBName(caller.ConnectionString);
images.Add(temp);
}
The problem ended up to be because I was using System.Data.SqlServerCe 3.5.1.0 when I switched to 3.5.0.0 it worked without any error.
And I put the while loop outside the catch statement.
But I'm still annoyed from MS because they didnt show any error regarding that!
Raym0nd, I'm guessing you are new at this.
Take a look at this version of what you provided.
public static List<Image> GetAll(BOI caller) {
List<Image> images = new List<Image>();
using (SqlCeCommand cmd = new SqlCeCommand("SELECT * FROM Images", Connection.GetConnection(caller.ConnectionString))) {
try {
cmd.Connection.Open();
using (SqlCeReader reader = cmd.ExecuteReader()) {
while (reader.Read()) {
object imageKey = reader["imageKey"];
object filename = reader["filename"];
object image = reader["image"];
object labelKey = reader["labelKey"];
object priority = reader["priority"];
Image img = new Image((interface)imageKey, (string)filename, (byte[])image, (int?)labelKey, (int)priority);
img.SetDBName(caller.ConnectionString);
images.Add(img);
}
}
} catch (SqlCeException err) {
Console.WriteLine(err.Message);
throw err;
} finally {
cmd.Connection.Close();
}
}
return images;
}
You'll want to add some functionality to test your objects in the case of your nullable integer, but for the most part is is clean and simple.
Put a break point on the Console.WriteLine(), and mouse over the Message if an exception occurs.

Categories

Resources