MapsterMapper / Mapster

A fast, fun and stimulating object to object Mapper
MIT License
4.38k stars 331 forks source link

Google.Protobuf.WellKnownTypes.Timestamp Error while compiling #718

Open npatersontemenos opened 5 months ago

npatersontemenos commented 5 months ago

Using GRPC, the proto class that maps to my POCO has one field of type google.protobuf.Timestamp, whereas, it is a datetime field in my poco. The error says "source=Google.Protobuf.WellKnownTypes.Timestamp destination=System.DateTime" and goes onto say: "Cannot convert immutable type, please consider using 'MapWith' method to create mapping". I assume this means in the configure RegisterMappings method? Can anyone steer me in the right direction to resolve this please? My code is similar to: TypeAdapterConfig<W1, W2>.NewConfig() .Map(dest => dest.dt, src => src.Dt1)

stagep commented 4 months ago
public class MapsterConfiguration : IRegister
{
    public void Register(TypeAdapterConfig config)
    {
        config.ForType<Timestamp, DateTime>().MapWith(d => d.ToDateTime());
        config.ForType<DateTime, Timestamp>().MapWith(d => Timestamp.FromDateTime(d));
    }
}
npatersontemenos commented 4 months ago

@stagep Many thanks!

Exzept1on commented 4 months ago
public class MapsterConfiguration : IRegister
{
    public void Register(TypeAdapterConfig config)
    {
        config.ForType<Timestamp, DateTime>().MapWith(d => d.ToDateTime());
        config.ForType<DateTime, Timestamp>().MapWith(d => Timestamp.FromDateTime(d));
    }
}

how to make the same, but with nullable datetime? because using nullable datetime throws the same error which described in topic

stagep commented 4 months ago

If DateTime is nullable then you have 2 options. Use a nullable Timestamp or create your own gRPC message that can handle the nullability of DateTime with a IsNull property. I use this approach.

config.ForType<Timestamp?, DateTime?>().MapWith(d => d == null ? null : d.ToDateTime());
config.ForType<DateTime?, Timestamp?>().MapWith(d => d.HasValue ? Timestamp.FromDateTime(d.Value) : null);

nullable_date_time.proto:

message NullableDateTimeMessage
{
    int32 year = 1;
    int32 month = 2;
    int32 day = 3;
    int32 hour = 4;
    int32 minute = 5;
    int32 second = 6;
    bool is_null = 7;
}

and the mapping

config.ForType<NullableDateTimeMessage, DateTime?>().MapWith(d => d.IsNull ? null : new DateTime(d.Year, d.Month, d.Day, d.Hour, d.Minute, d.Second);
config.ForType<DateTime?, NullableDateTimeMessage>().MapWith(d => d.HasValue ?
            new NullableDateTimeMessage { Year = d.Value.Year, Month = d.Value.Month, Day = d.Value.Day, Hour = d.Value.Hour, Minute = d.Value.Minute, Second = d.Value.Second } :
            new NullableDateTimeMessage { IsNull = true });
Exzept1on commented 4 months ago

Thanks for answer.

config.ForType<Timestamp?, DateTime?>().MapWith(d => d == null ? null : d.ToDateTime());

config.ForType<DateTime?, Timestamp?>().MapWith(d => d.HasValue ? DateTime.SpecifyKind(d.Value, DateTimeKind.Utc).ToTimestamp() : null);

This code works for me.