Convert a data row to a JSON object

后端 未结 4 1710
天涯浪人
天涯浪人 2020-12-11 16:08

I have a DataTable which has only a single row and looks like

   America              |  Africa               |     Japan     |   
   ----------         


        
相关标签:
4条回答
  • 2020-12-11 16:48

    Assuming you are using json.net, there is a special built-in converter, DataTableConverter, that outputs data tables in an abbreviated format as an array of rows where each row is serialized as column name/value pairs as shown in your question. While there is also a converter for DataSet, there is no specific built-in converter for DataRow. Thus when directly serializing a DataRow Json.NET will serialize all the fields and properties of the DataRow resulting in a more verbose output - which you do not want.

    The easiest way to serialize a DataRow in the more compact form used by DataTable is to serialize the entire table to a JArray using JArray.FromObject() and then pick out the array item with the same index as the DataRow you want to serialize:

    var rowIndex = 0;
    
    var jArray = JArray.FromObject(datatable, JsonSerializer.CreateDefault(new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }));
    
    var rowJToken = jArray[rowIndex];
    var rowJson = rowJToken.ToString(Formatting.Indented);  // Or Formatting.None if you prefer
    

    Since your table has only one row, rowIndex should be 0. More generally, if you don't know the index of a given DataRow, see How to get the row number from a datatable?.

    Demo fiddle #1 here.

    Alternatively, if your table is large enough that serializing the entire table has performance implications, you can introduce a custom JsonConverter for DataRow that writes the row to JSON as an object:

    public class DataRowConverter : JsonConverter<DataRow>
    {
        public override DataRow ReadJson(JsonReader reader, Type objectType, DataRow existingValue, bool hasExistingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException(string.Format("{0} is only implemented for writing.", this));
        }
    
        public override void WriteJson(JsonWriter writer, DataRow row, JsonSerializer serializer)
        {
            var table = row.Table;
            if (table == null)
                throw new JsonSerializationException("no table");
            var contractResolver = serializer.ContractResolver as DefaultContractResolver;
    
            writer.WriteStartObject();
            foreach (DataColumn col in row.Table.Columns)
            {
                var value = row[col];
    
                if (serializer.NullValueHandling == NullValueHandling.Ignore && (value == null || value == DBNull.Value))
                    continue;
    
                writer.WritePropertyName(contractResolver != null ? contractResolver.GetResolvedPropertyName(col.ColumnName) : col.ColumnName);
                serializer.Serialize(writer, value);
            }
            writer.WriteEndObject();
        }
    }
    

    And then use it like:

    var row = datatable.Rows[rowIndex];
    
    var settings = new JsonSerializerSettings
    {
        NullValueHandling = NullValueHandling.Ignore,
        Converters = { new DataRowConverter() },
    };
    var rowJson = JsonConvert.SerializeObject(row, Formatting.Indented, settings);
    

    Notes:

    • While it makes sense to serialize a single DataRow, it doesn't make sense to deserialize one since a DataRow is not a standalone object; it exists only inside some parent DataTable. Thus ReadJson() is not implemented.

    • JsonConverter<T> was introduces in Json.NET 11.0.1. In earlier versions inherit from JsonConverter.

    Demo fiddle #2 here.

    0 讨论(0)
  • 2020-12-11 16:51

    Spelling? Shouldn't your call to the "SerializeObject" method be:

    string js = JsonConvert.SerializeObject(datatable);
    

    Also see a similar question on converting a datatable to JSON string.

    0 讨论(0)
  • 2020-12-11 16:53

    As an alternative to the answer found here, you can use an ExpandoObject to quickly and pretty easily render a single row as JSON, as such:

    var expando = new System.Dynamic.ExpandoObject() as IDictionary<string, object>;
    foreach (DataColumn col in myRow.Table.Columns)
    {
        eo[col.ColumnName] = myRow[col];
    }
    var json = JsonConvert.SerializeObject(expando);
    
    0 讨论(0)
  • 2020-12-11 16:56

    Like Gazzi said you should include the NewtonSoft.Json library it is included in Visual Studio.

    To get an object similar to what you have described you should create a data model like Country.cs which would look like this.

    [Serializable]
    public class CountryModel {
       public int ID { get; set; }
       public string Title { get; set; }
       public List<ValueModel> Values { get; set; }
    }
    
    [Serializable]
    public class ValueModel {
       public int ValueID { get; set; }
       public string Type { get; set; }
    }
    

    Create a helper function to convert your table data to these models. You can then serialize/deserialize data as need using the Newtonsoft Library.

    0 讨论(0)
提交回复
热议问题