简体   繁体   中英

How do I bind a Boolean array to a C# model using Entity Framework Code First?

I am trying to serialize a JSON response into a Entity Framework Code First model.

The payload is as follows:

[{
 "_cs_regimen":"3_per_week",
 "_cs_account_email":"my@email.com",
 "_cs_results":[true,true,false], <<< ### The property in question ###
 "_cs_distance":[101018.52287999999,460594.25279999996],
 "_cs_joined_team_time":"2022-06-11T10:36:15.840649Z",
 "_cs_account_lastName":...

My model is as follows:

public class LeaderboardData
{
    [Key]
    public int LeaderboardId { get; set; }

    [DefaultValue(1)]
    public int Week { get; set; }
    ......

    public virtual LeaderboardRideResult _cs_results { get; set; } < I want to bind the boolean array into this property.
}

LeaderboardRideResult looks like this:

public class LeaderboardRideResult
{
    [Key]
    public int Id { get; set; }

    public string tag { get; set; }

    public List<bool> contents { get; set; }

    [ForeignKey("LeaderboardData")]
    public int LeaderboardDataId { get; set; }
}

And I have a mapping to bind the array back to a boolean list here:

protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<RiderOptIn>()
                .HasIndex(entity => new { entity._email, entity._username })
                .IsUnique();

            modelBuilder.Entity<LeaderboardRideResult>().Property(p => p.contents)
             .HasConversion(
                 v => JsonConvert.SerializeObject(v),
                 v => JsonConvert.DeserializeObject<List<bool>>(v));
                }

Deserialization code (Newtonsoft):

List<LeaderboardData> myDeserializedClass = JsonConvert.DeserializeObject<List<LeaderboardData>>(result); (result = the JSON above)

I'm getting this back:

Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'KiltedRiders.Models.LeaderboardRideResult' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
Path '[0]._cs_results', line 1, position 90.'

Any hints on this would be apprecaited.

Your C# model is not matching the incoming json type.

public virtual LeaderboardRideResult _cs_results { get; set; } public virtual LeaderboardRideResult _cs_results { get; set; } should be like

public virtual bool[] _cs_results { get; set; }

or

public virtual List<bool> _cs_results { get; set; }

Add another new property in your model for retrieve data:

    [NotMapped]
    [JsonProperty(PropertyName = "_cs_results")]
    public virtual List<bool> CsResult { get; set; }

Finally LeaderboardData model look like:

public class LeaderboardData
{

    public int LeaderboardId { get; set; }

    [DefaultValue(1)]
    public int Week { get; set; }
    [NotMapped]
    [JsonProperty(PropertyName = "_cs_results")]
    public virtual List<bool> CsResult { get; set; }
    public virtual LeaderboardRideResult _cs_results { get; set; }
}

As vaibhavit80 explained above the type you are trying to deserialize into is wrong. I suspect you will kick yourself when the penny drops:-)

I've stripped it right back, try running this and hopefully you will see the issue.

internal class Program
{

    public class LeaderboardRideResult
    {
        public List<bool> contents { get; set; }
    }

    public class LeaderboardData
    {
        public virtual LeaderboardRideResult _cs_results { get; set; } //  < I want to bind the boolean array into this property.
    }

    public class LeaderboardData_2
    {
        public virtual List<bool> _cs_results { get; set; } //  < I want to bind the boolean array into this property.
    }


    static void Main(string[] args)
    {
        var json = "{ \"_cs_results\":[true,true,false] }"; // <<< ### The property in question ###

        try
        {
            var myDeserializedClass = JsonConvert.DeserializeObject<LeaderboardData>(json);
        }
        catch (Exception x)
        {
            System.Console.WriteLine(x);
        }

        var myDeserializedClass2 = JsonConvert.DeserializeObject<LeaderboardData_2>(json);
    }
}

The exception caused by the first deserialization attempt is the same as the one you mention:

Newtonsoft.Json.JsonSerializationException: Cannot deserialize the current JSON array (eg [1,2,3]) into type 'DeserTest.Program+LeaderboardRideResult' because the type requires a JSON object (eg {"name":"value"}) to deserialize correctly. To fix this error either change the JSON to a JSON object (eg {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (eg ICollection, IList) like List that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array. Path '_cs_results', line 1, position 17. at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureArrayContract(JsonReader reader, Type objectType, JsonContract contract)....

The fact that it's an EF model is nothing to do with it. Neither is the fact that the property is virtual.

The issue is you are trying to serialize a bool array into a class.

Your json should be parseable and can be converted as an object. In case of your model structure, it is not. I can't see the relationship on your sample models, but you can try creating an entity for your Content property, like this:

public class Content 
{
    public int Id { get;set; }
    public bool Value { get;set; }

    [ForeignKey("LeaderboardRideResult")]
    public int LeaderboardRideResultId { get; set; }

    public virtual LeaderboardRideResult LeaderboardRideResult { get;set; }
}

And here, I updated minor name on your 2 existing models:

public class LeaderboardData
{
    [Key]
    public int LeaderboardId { get; set; }

    [DefaultValue(1)]
    public int Week { get; set; }
    ......

    public virtual LeaderboardRideResult LeaderboardRideResult { get; set; }
}

public class LeaderboardRideResult
{
    [Key]
    public int LeaderboardRideResultId { get; set; }

    public string Tag { get; set; }

    ...

    [ForeignKey("LeaderboardData")]
    public int LeaderboardDataId { get; set; }

    public ICollection<Content> Contents { get; set; }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM