Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wishlist: Support DateOnly properties #665

Open
perlun opened this issue Jan 24, 2023 · 3 comments
Open

Wishlist: Support DateOnly properties #665

perlun opened this issue Jan 24, 2023 · 3 comments

Comments

@perlun
Copy link

perlun commented Jan 24, 2023

Given the preconditions (that we need to support Netstandard 2.0+, .NET Framework 4.0 and 4.5+), I might be asking for the impossible here, but anyway... 🙂

Trying to read a DATE NOT NULL field in PostgreSQL, but it causes the following failure:

Unhandled Exception: System.InvalidCastException: Invalid cast from 'System.DateTime' to 'System.DateOnly'.
   at System.Convert.DefaultToType(IConvertible value, Type targetType, IFormatProvider provider)
   at System.DateTime.System.IConvertible.ToType(Type type, IFormatProvider provider)
   at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
   at PetaPoco.Core.PocoData.<>c__DisplayClass31_0.<GetConverter>b__4(Object src)
   at petapoco_factory_1(IDataReader )
   at PetaPoco.Database.ExecuteReader[T](CommandType commandType, String sql, Object[] args)+MoveNext()
   at System.Collections.Generic.LargeArrayBuilder`1.AddRange(IEnumerable`1 items)
   at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at System.Collections.Immutable.ImmutableExtensions.FallbackWrapper`1.get_Count()
   at System.Collections.Immutable.ImmutableList`1.CreateRange(IEnumerable`1 items)
   at System.Collections.Immutable.ImmutableList`1.AddRange(IEnumerable`1 items)
   at System.Collections.Immutable.ImmutableList.ToImmutableList[TSource](IEnumerable`1 source)
   at Poc.Hemekonomi.ConsoleApp.Program.CategorizeTransactions() in /home/per/git/poc.hemekonomi/Poc.Hemekonomi.ConsoleApp/Program.cs:line 137

My guess is that I need to resort to a custom converter, i.e. create a class which inherits from ValueConverterAttribute and override the methods there for now? 🤔 To manually handle such properties.


Would be awesome to be able to drop all "old" platforms here to be able to fully utilize the goodness of DateOnly, which is .NET 6 and 7 only... but I realize I might be one of the privileged few in this case, not having to deal with any legacy .NET codebases. 😁 (My day job is as a Java programmer. 😂)

@asherber
Copy link
Collaborator

I'll take a look at this, see what's going on. 

As someone who works with a number of codebases still on .NET Framework, I'm in favor of maintaining as much compatibility as possible. Conditional compiles can be your friend. In this case, explicitly supporting DateOnly would require adding a net6.0 compilation target to the package, but maybe there's something else that can be done.

In the short term, either a value converter or a custom mapper would be the way to go for you. A value converter would have to be applied to each DateOnly field, whereas a mapper (passed to the Database constructor) could handle them all at once.

@harley333
Copy link

@asherber , can you point me to an example of a custom-mapper (or provide a custom-mapper for the DateOnly type)?

@asherber
Copy link
Collaborator

There are several ways of going about this. Here's one.

create table date_test (Foo date not null);
insert into date_test (Foo) values ('2024-08-01');
class DateMapper : ConventionMapper
{
    public override Func<object, object> GetFromDbConverter(PropertyInfo targetProperty, Type sourceType)
    {
        // see if there's already a converter on the class/property
        var result = base.GetFromDbConverter(targetProperty, sourceType);
        
        if (result == null 
            && targetProperty.PropertyType == typeof(DateOnly) 
            && sourceType == typeof(DateTime))
        {            
            
            return o => DateOnly.FromDateTime((DateTime)o);
        }
        return result;
    }
}

class DateTest
{
    public DateOnly foo { get; set; }
}

using var db = new Database(Connection, new DateMapper());
var records = db.Fetch<DateTest>("select * from date_test");

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants