0
votes

Trying write a simple API to access a Db2 database table with packed decimal fields. Without converting the value, is there a corresponding data type in C#? I keep getting a mismatching data type error.

{"Specified cast is not valid."} Data: {System.Collections.ListDictionaryInternal} HResult: -2147467262 HelpLink: null InnerException: null Message: "Specified cast is not valid." Source: "IBM.Data.DB2.Core" StackTrace: " at IBM.Data.DB2.Core.DB2DataWrapper.get_Int32Value()\r\n at IBM.Data.DB2.Core.DB2DataReader.GetInt32(Int32 i)\r\n at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable1.AsyncEnumerator.<MoveNextAsync>d__17.MoveNext()\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.ValueTaskAwaiter1.GetResult()\r\n at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.d__221.MoveNext()\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.<SingleOrDefaultAsync>d__221.MoveNext()\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAw aiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()\r\n at CoreCodeCamp.Data.TestRepository.<GetAccountAsync>d__6.MoveNext() in TestRepository.cs:line 60\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()\r\n at CoreCodeCamp.Controllers.TestController.d__4.MoveNext() in TestController.cs:line 38" TargetSite: {Int32 get_Int32Value()}

Here is the code...

DB2 Camps table:

Field      Type  Length     
CAMPID     P     5,0    
NAME       A     50
MONIKER    A     20     
EVENTDATE  Z     26
LENGTH     S     3,0
LOCATIONID P     5,0

CampsController.cs:

[HttpGet]
public async Task<ActionResult<CampModel[]>> Get(bool includeTalks = false)
{
  try
  {
    var results = await _repository.GetAllCampsAsync(includeTalks);

    return _mapper.Map<CampModel[]>(results);
  }
  catch (Exception)
  {
    return this.StatusCode(StatusCodes.Status500InternalServerError, "Database Failure");
  }
}

DBcontext.cs:

using IBM.EntityFrameworkCore;
using IBM.EntityFrameworkCore.Storage.Internal;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseDb2(_config.GetConnectionString("CodeCamp"),
    p =>
    {
        p.SetServerInfo(IBMDBServerType.AS400, IBMDBServerVersion.AS400_07_01);
        p.UseRowNumberForPaging();
        p.MaxBatchSize(1);
    });

}

Camp.cs Entity:

namespace CoreCodeCamp.Data
{
    public class Camp
    {
        public int CampId { get; set; }
        public string Name { get; set; }
        public string Moniker { get; set; }
        public Location Location { get; set; }
        public DateTime EventDate { get; set; } = DateTime.MinValue;
        public int Length { get; set; } = 1;
        public ICollection<Talk> Talks { get; set; }
    }
}

Repository.cs:

public async Task<Camp[]> GetAllCampsAsync(bool includeTalks = false)
{
  _logger.LogInformation($"Getting all Camps");

  IQueryable<Camp> query = _context.Camps;

  return await query.ToArrayAsync();
}
1
It is IBM format. There are a few type. Do web search for "wiki ibm packed decimal"jdweng
DB2 is a IBM database which uses formats going back to the 1960's and packed decimal was used on punch cards. Over the years IBM improved some of these formats so there are many flavors of the the IBM formats.jdweng

1 Answers

2
votes

You should show your code...

But the IBM i .NET data provider should have a iDB2Decimal structure used for packed numeric.

iDB2Decimal.Value returns a C# Decimal type.

EDIT
ok, so you have both packed decimal CAMPID P 5,0
and zoned decimal LENGTH S 3,0

which should correspond to iDB2Decimal and iDB2Numeric.

Both of which have a Value property that returns a C# Decimal.

So I'd recommend changing your model from int to Decimal to those two fields.
Location is also packed in the DB, I'm not sure what you've done with your Location type... LOCATIONID P 5,0
public Location Location { get; set; }