Type Converters

3 posts, 0 answers
  1. Mensur
    Mensur avatar
    7 posts
    Member since:
    Aug 2011

    Posted 24 Oct 2011 Link to this post

    I am trying to get a type converter to work but the app is complaining that the converter cannot be found. I created a FluentAPI project and added a converter there by following this FluentAPI blog post and this type converters Blog post. I basically have two classes: Book and Identifier and if I don't have a type converter everything seems to be fine. I am trying to convert date/time to a text representation which is how the date/time is stored in SQLite database:
    public class SqliteDateToDateTime : AdoTypeConverter
    {
        private bool nullable;
     
        public override AdoTypeConverter Initialize(IDataColumn user, Type clr,
                                                         IAdoTypeConverterRegistry registry, bool secondaryTable)
        {
            //first we need to ensure that the clr type can be handled by this converter
            if (clr == typeof (DateTime) && user.ResolvedSqlType == "varchar")
            {
                //then we need to set a flag to determine if the type is nullable
                nullable = typeof (DateTime?) == clr;
     
                //finally return base.Initialize, which ultimatly returns "this"
                return base.Initialize(user, clr, registry, secondaryTable);
            }
     
            //if the converter can not work with the specified clr type we return null
            return null;
        }
     
        public override object Read(ref DataHolder holder)
        {
            //check if the value is dbnull
            bool isNull = holder.Reader.IsDBNull(holder.Position);
     
            //set wheather or not there is a value
            holder.NoValue = isNull;
     
            //if the value is null, then we need to return default values
            if (isNull)
            {
                //if the type is nullable, and the value is null, we simply return null
                if (nullable)
                    holder.ObjectValue = null;
                    //if the value is null, and we need to box it, we set the objectvalue to 0
                else if (holder.Box)
                    holder.ObjectValue = 0;
                else
                    //other wise the value is null, so we simply return the default int value
                    holder.Int32Value = 0;
            }
            else
            {
                //the value is not null, so here we want to pull the value out, and convert it to a string
                DateTime dt;
                string s = holder.Reader.GetValue(holder.Position).ToString();
                int index = s.IndexOf("+");
                if (index >= 0)
                {
                    dt = DateTime.Parse(s.Substring(0, s.IndexOf("+")));
                }
                else
                {
                    dt = DateTime.Parse(s);
                }
     
                //if the value is nullabel, or needs to be boxed, we set the ObjectValue Property of the DataHolder
                if (nullable || holder.Box)
                    holder.ObjectValue = dt;
                else
                    //otherwise we can set the Int32Value property to the parseed int value
                    holder.DateTimeValue = dt;
            }
     
            //now we return our value
            return holder.ObjectValue; // (holder.Box || nullable) ? holder.ObjectValue : null;
        }
     
        public override void Write(ref DataHolder holder)
        {
            //set the db type
            holder.Parameter.DbType = System.Data.DbType.String;
     
            //if there is no value we could specify what to set the db field to
            if (holder.NoValue)
            {
                //in this case we just want to set it to null
                holder.Parameter.Value = null;
            }
            else
            {
                //When there is a value we simply need to take our CLR int, and convert it to a string
                //and then set the parameter info
                string s = holder.DateTimeValue.ToString("yyyy-MM-dd HH:mm:ss+00:00");
                holder.Parameter.Size = s.Length;
                holder.Parameter.Value = s;
            }
        }
     
        public override bool CreateLiteralSql(ref DataHolder holder)
        {
            //If there is no value, then we just want to query against null.
            if (holder.NoValue)
            {
                holder.StringValue = "NULL";
     
                //returning false indicates that no quotes are required. We want NULL instead of 'NULL'
                return false;
            }
            else
            {
                //convert the int value into a string, since that is what we are storing it as in the db
                holder.StringValue = holder.DateTimeValue.ToString("yyyy-MM-dd HH:mm:ss+00:00");
     
                // return true indicates that quotes are needed around the value
                return true;
            }
        }
     
        public override Type DefaultType
        {
            get { return typeof (DateTime); }
        }
    }

        
    Again, the class is in the FluentAPI project and here is the PrepareMapping method:

    protected override IList<MappingConfiguration> PrepareMapping()
    {
        List<MappingConfiguration> configurations = new List<MappingConfiguration>();
     
        MappingConfiguration<Book> bookConfiguration = new MappingConfiguration<Book>();
        bookConfiguration.MapType(p => new
        {
            id = p.Id,
            title = p.Title
        }).ToTable("books");
        bookConfiguration.HasProperty(x => x.PublishedDate)
            .ToColumn("pubdate")
            .HasColumnType("text")
            .WithConverter<SqliteDateToDateTime>();
        bookConfiguration.HasProperty(p => p.Id).IsIdentity();
     
        MappingConfiguration<Identifier> identifierConfiguration = new MappingConfiguration<Identifier>();
        identifierConfiguration.MapType(p => new
        {
            id = p.Id,
            book = p.BookId,
            type = p.Type,
            val = p.Value
        }).ToTable("identifiers");
        identifierConfiguration.HasProperty(p => p.Id).IsIdentity();
     
        identifierConfiguration.HasAssociation(p => p.Book).WithOpposite(c => c.Identifiers).HasConstraint((p, c) => p.BookId == c.Id);
     
        configurations.Add(bookConfiguration);
        configurations.Add(identifierConfiguration);
        return configurations;
    }


    The error I am getting is this: Could not load type 'Data.SqliteDateToDateTime' from assembly 'Telerik.OpenAccess.Runtime, Version=2011.2.713.3, Culture=neutral, PublicKeyToken=7ce17eeaf1d59342'.":"Data.SqliteDateToDateTime"} System.Exception {System.TypeLoadException}.

    Any help is appreciated.



  2. Mensur
    Mensur avatar
    7 posts
    Member since:
    Aug 2011

    Posted 26 Oct 2011 Link to this post

    There must be someone who knows the answer to this?
  3. DevCraft banner
  4. Ady
    Admin
    Ady avatar
    589 posts

    Posted 28 Oct 2011 Link to this post

    Hello Mensur,

     I was able to reproduce the exception and we will fix this error. You can use the other overload of 'WithConverter' that use a string. Please change the code to the following:
    bookConfiguration.HasProperty(x => x.PublishedDate)
                    .ToColumn("pubdate")
                    .HasColumnType("text")
                    .WithConverter(typeof(SqliteDateToDateTime).AssemblyQualifiedName);

    Hope this helps.

    Do get back in case you need further assistance.

    Greetings,
    Ady
    the Telerik team

    NEW and UPDATED OpenAccess ORM Resources. Check them out!

Back to Top