ArgumentOutOfRangeException

Posts   
 
    
CowHills
User
Posts: 47
Joined: 14-Mar-2007
# Posted on: 27-Mar-2009 09:28:30   

Hello,

I've got a question regarding the exception as can be seen below. I've recently been trying to change my PKey from String to a unique identifier field. And instead of changing all the strings in the code to Guids I added a typeconverter to make this conversion. But when setting the Key the Exception occurs. I thought this could be fixed by editing the length in the type conversion editor screen, but this doesn't seem to help me.

Awaiting your answer, Paul

LLBLGen Pro version + buildnr = 2.0.0.0 Final

Runtime library version = 2.0.0.061220

StackTrace = [2009-03-26 06:03:34.750] [Error] [1] Error in Sales Message:System.ArgumentOutOfRangeException: The value specified will cause an overflow error in the database. Value length: 36. Column max. length: 0 Parameter name: LinePromotionId at SD.LLBLGen.Pro.ORMSupportClasses.EntityBase2.ValidateValue(IEntityField2 fieldToValidate, Object value, Int32 fieldIndex) at SD.LLBLGen.Pro.ORMSupportClasses.EntityBase2.SetNewFieldValue(Int32 fieldIndex, Object value, Boolean fireChangeEvent) at ORMapper.EntityClasses.LinePromotionEntity.SetNewFieldValue(Int32 fieldIndex, Object value) in \ORMapper\DatabaseGeneric\EntityClasses\LinePromotionEntity.cs:line 138 at ORMapper.EntityClasses.FinancialDiscountEntity.SetNewFieldValue(Int32 fieldIndex, Object value) in \ORMapper\DatabaseGeneric\EntityClasses\FinancialDiscountEntity.cs:line 128 at ORMapper.EntityClasses.LinePromotionEntity.set_LinePromotionId(String value) in \ORMapper\DatabaseGeneric\EntityClasses\LinePromotionEntity.cs:line 555 at ORMapper.EntityClasses.LinePromotionEntity.set_Key(String value) in \CustomEntities\LinePromotion.cs:line 122

.NET version = 3.5

database type = Sql Server 2005

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 27-Mar-2009 09:50:58   

If you have the time, I'd definitly recommend using the Guid all over the place. As I think it's not the most wise thing to do, to use a TypeConverter for the PK.

Anyway, would you please attach the TypeConverter class and the llblgen project?

Side note: I recommend you upgrade to the latest build of v.2.0 (that's a year later build than the one you have)

CowHills
User
Posts: 47
Joined: 14-Mar-2007
# Posted on: 27-Mar-2009 10:01:25   

Hello Walaa,

First of all, thanks for the quick response.

Here you will find the requested data.

About the side note: Good idea, do you think this could have something to do with the problem?

Paul

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 27-Mar-2009 10:20:39   

I wanted the source code of the Type Converter

CowHills
User
Posts: 47
Joined: 14-Mar-2007
# Posted on: 27-Mar-2009 10:24:29   

Ah, sorry.

Here's the code. The used class is GuidToStringTypeConverter.

Paul

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 30-Mar-2009 11:31:48   

Your TypeCoverter code is implemented the other way around, it's implemented to change from a database Guid to a .NET string.

I think you need the opposite.

to convert from a database field of type string, to a .NET field of type Guid, the ConvertFrom() method should return the Guid value.

And the ConvertTo() method should return the string value.

Also the CanConvertFrom() and CanConvertFrom() (which is not implemented by the way), both should check on the string type, and hence return true.

CowHills
User
Posts: 47
Joined: 14-Mar-2007
# Posted on: 30-Mar-2009 12:53:27   

I'll will look into it as soon as possible.

Thanks for all the help.

CowHills
User
Posts: 47
Joined: 14-Mar-2007
# Posted on: 31-Mar-2009 16:09:13   

Hi Wala,

I don't think that it is the other way around. My database has UniqueIdentifier fields and my project has String fields. All build fine, but when i try to assign (a valid) guid string value to the field, it gives me the ArgumentOutOfRange exception:

System.ArgumentOutOfRangeException: The value specified will cause an overflow error in the database. Value length: 36. Column max. length: 0

Also I've upgraded to the latest build.

Kind regards

MTrinder
User
Posts: 1461
Joined: 08-Oct-2008
# Posted on: 31-Mar-2009 21:20:20   

Is the type converter definitly set to be used (in the LLBLGen project) - can you stop a breakpoint in it when you try to set a valid GUID string value...?

It feels like it is not being used.

Matt

CowHills
User
Posts: 47
Joined: 14-Mar-2007
# Posted on: 31-Mar-2009 21:30:06   

Yes the typeconverter is set, but is going wrong before the typeconverter would be used. The exception occurs the moment I try to assign the fieldproperty.

I just found out that the problem fields all have a max length of 0 set in the generated FieldInfoProvider.cs. When I change these by hand to max length 36, all works well.

MTrinder
User
Posts: 1461
Joined: 08-Oct-2008
# Posted on: 31-Mar-2009 21:39:44   

Looks like it is doing the field length validation before using the type converter. I'll get someone to take a look at it for you.

Matt

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 01-Apr-2009 10:15:33   

Looking into it. Indeed, when the field has a typeconverter, the length etc. shouldn't be checked, as the real db type is unknown to the validation code. The problem is I think that in adapter for example, the entity doesn't know the field has a typeconverter....

So it's indeed really a designer thing, I think. Something we didn't think of. I'll look into how to solve this for you

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 01-Apr-2009 10:49:33   

The problem is indeed that the typeconverter isn't known inside the entity when a new value is set to a field: the typeconverter is part of the persistence info. (in SelfServicing this is known, but adapter it's not).

Another problem is that in the designer the field length is the length of the mapped target field. So no matter if you set a typeconverter, this length isn't changed. It's also not possible to set it manually through a plugin or patch, the length is the table/viewfield's length so modifying something in the designer isn't going to help, unfortunately.

This is clearly an oversight of the typeconverter system, what's so strange is that you're the first reporting this! (after all these years typeconverters are part of llblgen pro)

Anyway, you're stuck and want to get this solved. So there are two possibilities. 1) upgrade to v2.5 or v2.6. This lets you disable the built-in validation. It's a one-size-fits-all approach but at least you can make it work out fo the box (and for the fields you do want to validate on length, you can add a validator if you want). It does have an impact as there are breaking changes, so it might not be an option you can take at this point.

2) alter the Templates\SqlServer specific\NET 2.x\C#\persistenceInfoProviderAdapter.template template. The changes you've to make should emit a length of 32 for the fields which have a typeconverter and the fieldtype is of type 'string'. See code below


///////////////////////////////////////////////////////////////
// This is generated code. 
//////////////////////////////////////////////////////////////
// Code is generated using LLBLGen Pro version: <[LLBLGenVersion]>
// Code is generated on: <[Time]>
// Code is generated using templates: <[TemplateName]>
// Templates vendor: Solutions Design.
// Templates version: <[TemplateVersion]>
//////////////////////////////////////////////////////////////
using System;
using System.Collections;
using System.Data;

using SD.LLBLGen.Pro.ORMSupportClasses;

namespace <[RootNamespace]><[DbSpecificNamespaceSuffix]>
{
    /// <summary>
    /// Singleton implementation of the PersistenceInfoProvider. This class is the singleton wrapper through which the actual instance is retrieved.
    /// </summary>
    /// <remarks>It uses a single instance of an internal class. The access isn't marked with locks as the PersistenceInfoProviderBase class is threadsafe.</remarks>
    internal sealed class PersistenceInfoProviderSingleton
    {
        #region Class Member Declarations
        private static readonly IPersistenceInfoProvider _providerInstance = new PersistenceInfoProviderCore();
        #endregion
        
        /// <summary>private ctor to prevent instances of this class.</summary>
        private PersistenceInfoProviderSingleton()
        {
        }

        /// <summary>Dummy static constructor to make sure threadsafe initialization is performed.</summary>
        static PersistenceInfoProviderSingleton()
        {
        }

        /// <summary>Gets the singleton instance of the PersistenceInfoProviderCore</summary>
        /// <returns>Instance of the PersistenceInfoProvider.</returns>
        public static IPersistenceInfoProvider GetInstance()
        {
            return _providerInstance;
        }
    }

    /// <summary>Actual implementation of the PersistenceInfoProvider. Used by singleton wrapper.</summary>
    internal class PersistenceInfoProviderCore : PersistenceInfoProviderBase
    {
        /// <summary>Initializes a new instance of the <see cref="PersistenceInfoProviderCore"/> class.</summary>
        internal PersistenceInfoProviderCore()
        {
            Init();
        }

        /// <summary>Method which initializes the internal datastores with the structure of hierarchical types.</summary>
        private void Init()
        {
            base.InitClass((<[AmountOfElements Entity]> + <[AmountOfElements TypedView ]>));
<[Foreach Entity CrLf]>         Init<[CurrentEntityName]>EntityMappings();<[NextForeach]>
<[Foreach TypedView CrLf]>          Init<[CurrentTypedViewName]>TypedViewMappings();<[NextForeach]>
        }

<[Foreach Entity ]>
        /// <summary>Inits <[CurrentEntityName]>Entity's mappings</summary>
        private void Init<[CurrentEntityName]>EntityMappings()
        {
            base.AddElementMapping( "<[CurrentEntityName]>Entity", "<[ElementTargetCatalogName]>", @"<[ElementTargetSchemaName]>", "<[ElementTargetObjectName]>", <[AmountOfEntityFields]> );
<[If HasFields]><[Foreach EntityField CrLf]>            base.AddElementFieldMapping( "<[CurrentEntityName]>Entity", "<[EntityFieldName]>", "<[SourceColumnName]>", <[SourceColumnIsNullable]>, (int)SqlDbType.<[SourceColumnDbType]>, <[If HasTypeConverterDefined]><[If StringValueEquals TypeOfField "System.String"]>32<[Else]><[SourceColumnMaxLength]><[EndIf]><[Else]><[SourceColumnMaxLength]><[EndIf]>, <[SourceColumnScale]>, <[SourceColumnPrecision]>, <[IsIdentity]>, "<[IdentityValueSequenceName]>", <[If HasTypeConverterDefined]> new <[TypeConverterFullName]>()<[Else]>null<[EndIf]>, typeof(<[TypeOfMappedTargetField]>), <[ FieldIndex ]> );<[NextForeach]><[EndIf]>
        }<[NextForeach]>
<[Foreach TypedView]>
        /// <summary>Inits <[CurrentEntityName]>View's mappings</summary>
        private void Init<[CurrentTypedViewName]>TypedViewMappings()
        {
            base.AddElementMapping( "<[CurrentTypedViewName]>TypedView", "<[ElementTargetCatalogName]>", @"<[ElementTargetSchemaName]>", "<[ElementTargetObjectName]>", <[AmountOfTypedViewFields]> );
<[If HasFields]><[Foreach TypedViewField CrLf]>         base.AddElementFieldMapping( "<[CurrentTypedViewName]>TypedView", "<[TypedViewFieldName]>", "<[SourceColumnName]>", false, (int)SqlDbType.<[SourceColumnDbType]>, <[SourceColumnMaxLength]>, <[SourceColumnScale]>, <[SourceColumnPrecision]>,false, string.Empty, <[If HasTypeConverterDefined]> new <[TypeConverterFullName]>()<[Else]>null<[EndIf]>, typeof(<[TypeOfMappedTargetField]>), <[ FieldIndex ]> );<[NextForeach]><[EndIf]>
        }<[NextForeach]>
    }
}

I've altered the Init routine for entity fields. If you look at it closely, I've added two if statements: one which tests if there's a typeconverter and inside that if-statement if the fieldtype is System.String. If it is, I emit 32, otherwise I emit the original length. Length is only used as check for arrays and strings.

I haven't tested it in full as your project wouldn't load (couldn't load the shared classes assembly) but it should work OK. To use this altered template, you could either simply overwrite the original, though you could also create a new templatebindings file (e.g. through templatestudio) and bind the above template to the same templateid as teh original, and place the templatebindings file above the sqlserver specific templatebindings at tab 2 in the generator config dialog. Be sure your templatebindings file and template are readable by the designer (so in a folder they can reach).

If the template generates errors, please let me know.

Frans Bouma | Lead developer LLBLGen Pro
CowHills
User
Posts: 47
Joined: 14-Mar-2007
# Posted on: 01-Apr-2009 14:21:38   

Thanks Otis,

Will look into it asap. Upgrading to 2.5 or 2.6 is not an option at the moment.

Regards,