Change field to which data is saved for a data type if provided in prevalues and handle potential mis-matched types on display
This commit is contained in:
@@ -419,6 +419,12 @@ namespace Umbraco.Core
|
||||
/// Alias for the email address property editor
|
||||
/// </summary>
|
||||
public const string EmailAddressAlias = "Umbraco.EmailAddress";
|
||||
|
||||
/// <summary>
|
||||
/// Pre-value name used to indicate a field that can be used to override the database field to which data for the associated
|
||||
/// property is saved
|
||||
/// </summary>
|
||||
public const string DataValueTypePreValueKey = "umbracoDataValueType";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,10 +6,6 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Enum of the various DbTypes for which the Property values are stored
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Object is added to support complex values from PropertyEditors,
|
||||
/// but will be saved under the Ntext column.
|
||||
/// </remarks>
|
||||
[Serializable]
|
||||
[DataContract]
|
||||
public enum DataTypeDatabaseType
|
||||
|
||||
@@ -124,10 +124,54 @@ namespace Umbraco.Core.Models
|
||||
bool typeValidation = _propertyType.IsPropertyTypeValid(value);
|
||||
|
||||
if (typeValidation == false)
|
||||
throw new Exception(
|
||||
string.Format(
|
||||
"Type validation failed. The value type: '{0}' does not match the DataType in PropertyType with alias: '{1}'",
|
||||
value == null ? "null" : value.GetType().Name, Alias));
|
||||
{
|
||||
// Normally we'll throw an exception here. However if the property is of a type that can have it's data field (dataInt, dataVarchar etc.)
|
||||
// changed, we might have a value of the now "wrong" type. As of May 2016 Label is the only built-in property editor that supports this.
|
||||
// In that case we should try to parse the value and return null if that's not possible rather than throwing an exception.
|
||||
if (value != null && _propertyType.CanHaveDataValueTypeChanged())
|
||||
{
|
||||
var stringValue = value.ToString();
|
||||
switch (_propertyType.DataTypeDatabaseType)
|
||||
{
|
||||
case DataTypeDatabaseType.Nvarchar:
|
||||
case DataTypeDatabaseType.Ntext:
|
||||
value = stringValue;
|
||||
break;
|
||||
case DataTypeDatabaseType.Integer:
|
||||
int integerValue;
|
||||
if (int.TryParse(stringValue, out integerValue) == false)
|
||||
{
|
||||
// Edge case, but if changed from decimal --> integer, the above tryparse will fail. So we'll try going
|
||||
// via decimal too to return the integer value rather than zero.
|
||||
decimal decimalForIntegerValue;
|
||||
if (decimal.TryParse(stringValue, out decimalForIntegerValue))
|
||||
{
|
||||
integerValue = (int)decimalForIntegerValue;
|
||||
}
|
||||
}
|
||||
|
||||
value = integerValue;
|
||||
break;
|
||||
case DataTypeDatabaseType.Decimal:
|
||||
decimal decimalValue;
|
||||
decimal.TryParse(stringValue, out decimalValue);
|
||||
value = decimalValue;
|
||||
break;
|
||||
case DataTypeDatabaseType.Date:
|
||||
DateTime dateValue;
|
||||
DateTime.TryParse(stringValue, out dateValue);
|
||||
value = dateValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(
|
||||
string.Format(
|
||||
"Type validation failed. The value type: '{0}' does not match the DataType in PropertyType with alias: '{1}'",
|
||||
value == null ? "null" : value.GetType().Name, Alias));
|
||||
}
|
||||
}
|
||||
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -425,6 +426,19 @@ namespace Umbraco.Core.Models
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks the underlying property editor prevalues to see if the one that allows changing of the database field
|
||||
/// to which data is saved (dataInt, dataVarchar etc.) is included. If so that means the field could be changed when the data
|
||||
/// type is saved.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal bool CanHaveDataValueTypeChanged()
|
||||
{
|
||||
var propertyEditor = PropertyEditorResolver.Current.GetByAlias(_propertyEditorAlias);
|
||||
return propertyEditor.PreValueEditor.Fields
|
||||
.SingleOrDefault(x => x.Key == Constants.PropertyEditors.DataValueTypePreValueKey) != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the Value from a Property according to the validation settings
|
||||
/// </summary>
|
||||
|
||||
@@ -130,20 +130,20 @@ namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
switch (ValueType.ToUpper(CultureInfo.InvariantCulture))
|
||||
{
|
||||
case "INT":
|
||||
case "INTEGER":
|
||||
case PropertyEditorValueTypes.IntegerType:
|
||||
case PropertyEditorValueTypes.IntegerTypeAlternative:
|
||||
return DataTypeDatabaseType.Integer;
|
||||
case "DECIMAL":
|
||||
case PropertyEditorValueTypes.DecimalType:
|
||||
return DataTypeDatabaseType.Decimal;
|
||||
case "STRING":
|
||||
case PropertyEditorValueTypes.StringType:
|
||||
return DataTypeDatabaseType.Nvarchar;
|
||||
case "TEXT":
|
||||
case "JSON":
|
||||
case "XML":
|
||||
case PropertyEditorValueTypes.TextType:
|
||||
case PropertyEditorValueTypes.JsonType:
|
||||
case PropertyEditorValueTypes.XmlType:
|
||||
return DataTypeDatabaseType.Ntext;
|
||||
case "DATETIME":
|
||||
case "DATE":
|
||||
case "TIME":
|
||||
case PropertyEditorValueTypes.DateTimeType:
|
||||
case PropertyEditorValueTypes.DateType:
|
||||
case PropertyEditorValueTypes.TimeType:
|
||||
return DataTypeDatabaseType.Date;
|
||||
default:
|
||||
throw new FormatException("The ValueType does not match a known value type");
|
||||
|
||||
@@ -504,6 +504,8 @@ namespace Umbraco.Core.Services
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition), this))
|
||||
return;
|
||||
|
||||
OverrideDatabaseTypeIfProvidedInPreValues(dataTypeDefinition, values);
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow))
|
||||
{
|
||||
@@ -523,6 +525,36 @@ namespace Umbraco.Core.Services
|
||||
Audit(AuditType.Save, string.Format("Save DataTypeDefinition performed by user"), userId, dataTypeDefinition.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the database data field is provided in the pre-values update the data type definition to that instead of the
|
||||
/// default for the property editor
|
||||
/// </summary>
|
||||
/// <param name="dataTypeDefinition"></param>
|
||||
/// <param name="values"></param>
|
||||
private static void OverrideDatabaseTypeIfProvidedInPreValues(IDataTypeDefinition dataTypeDefinition, IDictionary<string, PreValue> values)
|
||||
{
|
||||
if (values != null && values.ContainsKey(Constants.PropertyEditors.DataValueTypePreValueKey))
|
||||
{
|
||||
switch (values[Constants.PropertyEditors.DataValueTypePreValueKey].Value)
|
||||
{
|
||||
case PropertyEditorValueTypes.StringType:
|
||||
dataTypeDefinition.DatabaseType = DataTypeDatabaseType.Nvarchar;
|
||||
break;
|
||||
case PropertyEditorValueTypes.IntegerType:
|
||||
dataTypeDefinition.DatabaseType = DataTypeDatabaseType.Integer;
|
||||
break;
|
||||
case PropertyEditorValueTypes.DecimalType:
|
||||
dataTypeDefinition.DatabaseType = DataTypeDatabaseType.Decimal;
|
||||
break;
|
||||
case PropertyEditorValueTypes.DateTimeType:
|
||||
dataTypeDefinition.DatabaseType = DataTypeDatabaseType.Date;
|
||||
break;
|
||||
case PropertyEditorValueTypes.TextType:
|
||||
dataTypeDefinition.DatabaseType = DataTypeDatabaseType.Ntext;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes an <see cref="IDataTypeDefinition"/>
|
||||
|
||||
@@ -41,7 +41,6 @@ namespace Umbraco.Web.PropertyEditors
|
||||
|
||||
internal class LabelPreValueEditor : PreValueEditor
|
||||
{
|
||||
private const string ValueTypeKey = "valueType";
|
||||
private const string LegacyPropertyEditorValuesKey = "values";
|
||||
|
||||
public LabelPreValueEditor()
|
||||
@@ -56,7 +55,7 @@ namespace Umbraco.Web.PropertyEditors
|
||||
ValueType = PropertyEditorValueTypes.StringType;
|
||||
}
|
||||
|
||||
[PreValueField(ValueTypeKey, "Value type", "valuetype")]
|
||||
[PreValueField(Constants.PropertyEditors.DataValueTypePreValueKey, "Value type", "valuetype")]
|
||||
public string ValueType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -72,19 +71,19 @@ namespace Umbraco.Web.PropertyEditors
|
||||
|
||||
// Check for a saved value type. If not found set to default string type.
|
||||
var valueType = PropertyEditorValueTypes.StringType;
|
||||
if (existing.ContainsKey(ValueTypeKey))
|
||||
if (existing.ContainsKey(Constants.PropertyEditors.DataValueTypePreValueKey))
|
||||
{
|
||||
valueType = (string)existing[ValueTypeKey];
|
||||
valueType = (string)existing[Constants.PropertyEditors.DataValueTypePreValueKey];
|
||||
}
|
||||
|
||||
// Convert any other values from a legacy property editor to a list, easier to enumerate on the editor.
|
||||
// Make sure to exclude values defined on the label property editor itself.
|
||||
var asList = existing
|
||||
.Select(e => new KeyValuePair<string, object>(e.Key, e.Value))
|
||||
.Where(e => e.Key != ValueTypeKey)
|
||||
.Where(e => e.Key != Constants.PropertyEditors.DataValueTypePreValueKey)
|
||||
.ToList();
|
||||
|
||||
var result = new Dictionary<string, object> { { ValueTypeKey, valueType } };
|
||||
var result = new Dictionary<string, object> { { Constants.PropertyEditors.DataValueTypePreValueKey, valueType } };
|
||||
if (asList.Any())
|
||||
{
|
||||
result.Add("values", asList);
|
||||
|
||||
Reference in New Issue
Block a user