/// <summary> /// Converts a property value to a string. /// </summary> public virtual string ConvertDbToString(IPropertyType propertyType, object value) { if (value == null) { return(string.Empty); } switch (ValueTypes.ToStorageType(ValueType)) { case ValueStorageType.Nvarchar: case ValueStorageType.Ntext: return(value.ToXmlString <string>()); case ValueStorageType.Integer: case ValueStorageType.Decimal: return(value.ToXmlString(value.GetType())); case ValueStorageType.Date: //treat dates differently, output the format as xml format var date = value.TryConvertTo <DateTime?>(); if (date.Success == false || date.Result == null) { return(string.Empty); } return(date.Result.ToXmlString <DateTime>()); default: throw new ArgumentOutOfRangeException(); } }
/// <summary> /// A method used to format the database value to a value that can be used by the editor /// </summary> /// <param name="property"></param> /// <param name="dataTypeService"></param> /// <param name="culture"></param> /// <param name="segment"></param> /// <returns></returns> /// <remarks> /// The object returned will automatically be serialized into json notation. For most property editors /// the value returned is probably just a string but in some cases a json structure will be returned. /// </remarks> public virtual object ToEditor(IProperty property, string culture = null, string segment = null) { var val = property.GetValue(culture, segment); if (val == null) { return(string.Empty); } switch (ValueTypes.ToStorageType(ValueType)) { case ValueStorageType.Ntext: case ValueStorageType.Nvarchar: //if it is a string type, we will attempt to see if it is json stored data, if it is we'll try to convert //to a real json object so we can pass the true json object directly to angular! var asString = val.ToString(); if (asString.DetectIsJson()) { try { var json = _jsonSerializer.Deserialize <dynamic>(asString); return(json); } catch { //swallow this exception, we thought it was json but it really isn't so continue returning a string } } return(asString); case ValueStorageType.Integer: case ValueStorageType.Decimal: //Decimals need to be formatted with invariant culture (dots, not commas) //Anything else falls back to ToString() var decim = val.TryConvertTo <decimal>(); return(decim.Success ? decim.Result.ToString(NumberFormatInfo.InvariantInfo) : val.ToString()); case ValueStorageType.Date: var date = val.TryConvertTo <DateTime?>(); if (date.Success == false || date.Result == null) { return(string.Empty); } //Dates will be formatted as yyyy-MM-dd HH:mm:ss return(date.Result.Value.ToIsoString()); default: throw new ArgumentOutOfRangeException(); } }
/// <summary> /// Used to try to convert the string value to the correct CLR type based on the DatabaseDataType specified for this value editor /// </summary> /// <param name="value"></param> /// <returns></returns> internal Attempt <object> TryConvertValueToCrlType(object value) { // if (value is JValue) // value = value.ToString(); //this is a custom check to avoid any errors, if it's a string and it's empty just make it null if (value is string s && string.IsNullOrWhiteSpace(s)) { value = null; } Type valueType; //convert the string to a known type switch (ValueTypes.ToStorageType(ValueType)) { case ValueStorageType.Ntext: case ValueStorageType.Nvarchar: valueType = typeof(string); break; case ValueStorageType.Integer: //ensure these are nullable so we can return a null if required //NOTE: This is allowing type of 'long' because I think json.net will deserialize a numerical value as long // instead of int. Even though our db will not support this (will get truncated), we'll at least parse to this. valueType = typeof(long?); //if parsing is successful, we need to return as an Int, we're only dealing with long's here because of json.net, we actually //don't support long values and if we return a long value it will get set as a 'long' on the Property.Value (object) and then //when we compare the values for dirty tracking we'll be comparing an int -> long and they will not match. var result = value.TryConvertTo(valueType); return(result.Success && result.Result != null ? Attempt <object> .Succeed((int)(long)result.Result) : result); case ValueStorageType.Decimal: //ensure these are nullable so we can return a null if required valueType = typeof(decimal?); break; case ValueStorageType.Date: //ensure these are nullable so we can return a null if required valueType = typeof(DateTime?); break; default: throw new ArgumentOutOfRangeException(); } return(value.TryConvertTo(valueType)); }
/// <summary> /// A method used to format the database value to a value that can be used by the editor /// </summary> /// <param name="property"></param> /// <param name="culture"></param> /// <param name="segment"></param> /// <returns></returns> /// <remarks> /// The object returned will always be a string and if the database type is not a valid string type an exception is thrown /// </remarks> public override object ToEditor(IProperty property, string culture = null, string segment = null) { var val = property.GetValue(culture, segment); if (val == null) { return(string.Empty); } switch (ValueTypes.ToStorageType(ValueType)) { case ValueStorageType.Ntext: case ValueStorageType.Nvarchar: return(val.ToString()); case ValueStorageType.Integer: case ValueStorageType.Decimal: case ValueStorageType.Date: default: throw new InvalidOperationException("The " + typeof(TextOnlyValueEditor) + " can only be used with string based property editors"); } }
/// <summary> /// Converts a property value to an Xml fragment. /// </summary> /// <remarks> /// <para>By default, this returns the value of ConvertDbToString but ensures that if the db value type is /// NVarchar or NText, the value is returned as a CDATA fragment - else it's a Text fragment.</para> /// <para>Returns an XText or XCData instance which must be wrapped in a element.</para> /// <para>If the value is empty we will not return as CDATA since that will just take up more space in the file.</para> /// </remarks> public XNode ConvertDbToXml(IPropertyType propertyType, object value) { //check for null or empty value, we don't want to return CDATA if that is the case if (value == null || value.ToString().IsNullOrWhiteSpace()) { return(new XText(ConvertDbToString(propertyType, value))); } switch (ValueTypes.ToStorageType(ValueType)) { case ValueStorageType.Date: case ValueStorageType.Integer: case ValueStorageType.Decimal: return(new XText(ConvertDbToString(propertyType, value))); case ValueStorageType.Nvarchar: case ValueStorageType.Ntext: //put text in cdata return(new XCData(ConvertDbToString(propertyType, value))); default: throw new ArgumentOutOfRangeException(); } }
/// <summary> /// A method to deserialize the string value that has been saved in the content editor /// to an object to be stored in the database. /// </summary> /// <param name="editorValue"></param> /// <param name="currentValue"> /// The current value that has been persisted to the database for this editor. This value may be useful for /// how the value then get's deserialized again to be re-persisted. In most cases it will probably not be used. /// </param> /// <param name="languageId"></param> /// <param name="segment"></param> /// <returns></returns> /// <remarks> /// By default this will attempt to automatically convert the string value to the value type supplied by ValueType. /// /// If overridden then the object returned must match the type supplied in the ValueType, otherwise persisting the /// value to the DB will fail when it tries to validate the value type. /// </remarks> public virtual object FromEditor(ContentPropertyData editorValue, object currentValue) { //if it's json but it's empty json, then return null if (ValueType.InvariantEquals(ValueTypes.Json) && editorValue.Value != null && editorValue.Value.ToString().DetectIsEmptyJson()) { return(null); } var result = TryConvertValueToCrlType(editorValue.Value); if (result.Success == false) { StaticApplicationLogging.Logger.LogWarning("The value {EditorValue} cannot be converted to the type {StorageTypeValue}", editorValue.Value, ValueTypes.ToStorageType(ValueType)); return(null); } return(result.Result); }