|
@@ -332,6 +332,7 @@ namespace InABox.Core
|
|
|
|
|
|
private UserProperties _userproperties;
|
|
private UserProperties _userproperties;
|
|
|
|
|
|
|
|
+ [DoNotPersist]
|
|
public UserProperties UserProperties
|
|
public UserProperties UserProperties
|
|
{
|
|
{
|
|
get
|
|
get
|
|
@@ -368,6 +369,35 @@ namespace InABox.Core
|
|
#endregion
|
|
#endregion
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ public class BaseObjectSnapshot<T>
|
|
|
|
+ where T : BaseObject
|
|
|
|
+ {
|
|
|
|
+ private List<(IProperty, object?)> Values;
|
|
|
|
+
|
|
|
|
+ private T Object;
|
|
|
|
+
|
|
|
|
+ public BaseObjectSnapshot(T obj)
|
|
|
|
+ {
|
|
|
|
+ Values = new List<(IProperty, object?)>();
|
|
|
|
+ foreach(var property in DatabaseSchema.Properties(obj.GetType()))
|
|
|
|
+ {
|
|
|
|
+ Values.Add((property, property.Getter()(obj)));
|
|
|
|
+ }
|
|
|
|
+ Object = obj;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public void ResetObject()
|
|
|
|
+ {
|
|
|
|
+ Object.CancelChanges();
|
|
|
|
+
|
|
|
|
+ var bObs = Object.IsObserving();
|
|
|
|
+ Object.SetObserving(false);
|
|
|
|
+ foreach(var (prop, value) in Values)
|
|
|
|
+ prop.Setter()(Object, value);
|
|
|
|
+ Object.SetObserving(bObs);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
public static class BaseObjectExtensions
|
|
public static class BaseObjectExtensions
|
|
{
|
|
{
|
|
public static bool HasColumn<T>(this T sender, string column)
|
|
public static bool HasColumn<T>(this T sender, string column)
|
|
@@ -393,122 +423,78 @@ namespace InABox.Core
|
|
: default;
|
|
: default;
|
|
}
|
|
}
|
|
|
|
|
|
- public static Dictionary<string, object> GetValues<T>(this T sender, bool all, bool followlinks = false) where T : BaseObject
|
|
|
|
|
|
+ public static Dictionary<string, object?> GetValues<T>(this T sender, bool all) where T : BaseObject
|
|
{
|
|
{
|
|
- var result = new Dictionary<string, object>();
|
|
|
|
- LoadValues(sender, result, "", all, false, followlinks);
|
|
|
|
- return result;
|
|
|
|
- }
|
|
|
|
|
|
+ var result = new Dictionary<string, object?>();
|
|
|
|
|
|
- public static void SetValues<T>(this T sender, Dictionary<string, object> values)
|
|
|
|
- {
|
|
|
|
- foreach (var value in values)
|
|
|
|
- CoreUtils.SetPropertyValue(sender, value.Key, value.Value);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public static Dictionary<string, object> GetOriginaValues<T>(this T sender, bool all) where T : BaseObject
|
|
|
|
- {
|
|
|
|
- var result = new Dictionary<string, object>();
|
|
|
|
- LoadValues(sender, result, "", all, true);
|
|
|
|
- return result;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private static void LoadValues(BaseObject sender, Dictionary<string, object?> values, string prefix, bool all, bool original, bool followlinks = false)
|
|
|
|
- {
|
|
|
|
- try
|
|
|
|
|
|
+ foreach(var property in DatabaseSchema.Properties(sender.GetType()))
|
|
{
|
|
{
|
|
- var props = sender.GetType().GetProperties().Where(x =>
|
|
|
|
- x.GetCustomAttribute<DoNotSerialize>() == null
|
|
|
|
- && x.GetCustomAttribute<DoNotPersist>() == null
|
|
|
|
- && x.GetCustomAttribute<AggregateAttribute>() == null
|
|
|
|
- && x.GetCustomAttribute<FormulaAttribute>() == null
|
|
|
|
- && x.GetCustomAttribute<ConditionAttribute>() == null
|
|
|
|
- && x.GetCustomAttribute<ChildEntityAttribute>() == null
|
|
|
|
- && x.CanWrite);
|
|
|
|
- foreach (var prop in props)
|
|
|
|
- if (prop.PropertyType.GetInterfaces().Contains(typeof(IEnclosedEntity)))
|
|
|
|
- {
|
|
|
|
- var child = prop.GetValue(sender) as BaseObject;
|
|
|
|
- if (child != null)
|
|
|
|
- LoadValues(child, values, string.IsNullOrWhiteSpace(prefix) ? prop.Name : prefix + "." + prop.Name, all, original, followlinks);
|
|
|
|
- }
|
|
|
|
- else if (prop.PropertyType.GetInterfaces().Contains(typeof(IEntityLink)))
|
|
|
|
|
|
+ if (property.IsDBColumn)
|
|
|
|
+ {
|
|
|
|
+ var isLocal = !property.HasParentEntityLink()
|
|
|
|
+ || (property.Parent?.HasParentEntityLink() != true && property.Name.EndsWith(".ID"));
|
|
|
|
+ if (isLocal)
|
|
{
|
|
{
|
|
- var child = prop.GetValue(sender) as BaseObject;
|
|
|
|
- if (child != null)
|
|
|
|
|
|
+ if (all)
|
|
{
|
|
{
|
|
- if (all)
|
|
|
|
- {
|
|
|
|
- values[string.IsNullOrWhiteSpace(prefix) ? prop.Name + ".ID" : prefix + "." + prop.Name + ".ID"] =
|
|
|
|
- original
|
|
|
|
- ? child.OriginalValues.ContainsKey("ID") ? child.OriginalValues["ID"] : Guid.Empty
|
|
|
|
- : CoreUtils.GetPropertyValue(child, "ID");
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- if (child.HasOriginalValue("ID"))
|
|
|
|
- values[string.IsNullOrWhiteSpace(prefix) ? prop.Name + ".ID" : prefix + "." + prop.Name + ".ID"] =
|
|
|
|
- original
|
|
|
|
- ? child.OriginalValues.ContainsKey("ID") ? child.OriginalValues["ID"] : Guid.Empty
|
|
|
|
- : CoreUtils.GetPropertyValue(child, "ID");
|
|
|
|
- }
|
|
|
|
- if (followlinks)
|
|
|
|
- LoadValues(child, values, string.IsNullOrWhiteSpace(prefix) ? prop.Name : prefix + "." + prop.Name, all, original, followlinks);
|
|
|
|
|
|
+ result[property.Name] = property.Getter()(sender);
|
|
}
|
|
}
|
|
- }
|
|
|
|
- else if (prop.PropertyType.GetInterfaces().Contains(typeof(IBaseObject)))
|
|
|
|
- {
|
|
|
|
- var child = prop.GetValue(sender) as IBaseObject;
|
|
|
|
- if (child != null)
|
|
|
|
|
|
+ else
|
|
{
|
|
{
|
|
- if (all)
|
|
|
|
|
|
+ if(property is StandardProperty stdProp)
|
|
{
|
|
{
|
|
- values[string.IsNullOrWhiteSpace(prefix) ? prop.Name : prefix + "." + prop.Name] = child;
|
|
|
|
|
|
+ var parent = property.Parent != null ? property.Parent.Getter()(sender) as BaseObject : sender;
|
|
|
|
+ if(parent?.HasOriginalValue(stdProp.Property.Name) == true)
|
|
|
|
+ {
|
|
|
|
+ result[property.Name] = property.Getter()(sender);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- else
|
|
|
|
|
|
+ else if(property is CustomProperty customProp)
|
|
{
|
|
{
|
|
- if (child.IsChanged())
|
|
|
|
- values[string.IsNullOrWhiteSpace(prefix) ? prop.Name : prefix + "." + prop.Name] = child;
|
|
|
|
|
|
+ if (sender.HasOriginalValue(customProp.Name))
|
|
|
|
+ {
|
|
|
|
+ result[property.Name] = property.Getter()(sender);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- else
|
|
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static Dictionary<string, object?> GetOriginaValues<T>(this T sender) where T : BaseObject
|
|
|
|
+ {
|
|
|
|
+ var result = new Dictionary<string, object?>();
|
|
|
|
+
|
|
|
|
+ foreach(var property in DatabaseSchema.Properties(sender.GetType()))
|
|
|
|
+ {
|
|
|
|
+ if (property.IsDBColumn)
|
|
|
|
+ {
|
|
|
|
+ var isLocal = !property.HasParentEntityLink()
|
|
|
|
+ || (property.Parent?.HasParentEntityLink() != true && property.Name.EndsWith(".ID"));
|
|
|
|
+ if (isLocal)
|
|
{
|
|
{
|
|
- if (all)
|
|
|
|
- {
|
|
|
|
- values[string.IsNullOrWhiteSpace(prefix) ? prop.Name : prefix + "." + prop.Name] =
|
|
|
|
- original
|
|
|
|
- ? sender.OriginalValues.ContainsKey(prop.Name) ? sender.OriginalValues[prop.Name] : prop.PropertyType.GetDefault()
|
|
|
|
- : prop.GetValue(sender);
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
|
|
+ var parent = property.Parent != null ? property.Parent.Getter()(sender) as BaseObject : sender;
|
|
|
|
+ var localPropName = property is StandardProperty stdProp ? stdProp.Property.Name : property.Name;
|
|
|
|
+ if(parent?.OriginalValues.TryGetValue(localPropName, out var original) == true)
|
|
{
|
|
{
|
|
- if (sender.HasOriginalValue(prop.Name))
|
|
|
|
- values[string.IsNullOrWhiteSpace(prefix) ? prop.Name : prefix + "." + prop.Name] =
|
|
|
|
- original
|
|
|
|
- ? sender.OriginalValues.ContainsKey(prop.Name)
|
|
|
|
- ? sender.OriginalValues[prop.Name]
|
|
|
|
- : prop.PropertyType.GetDefault()
|
|
|
|
- : prop.GetValue(sender);
|
|
|
|
|
|
+ result[property.Name] = original;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
- var iprops = DatabaseSchema.Properties(sender.GetType()).Where(x => x is CustomProperty);
|
|
|
|
- foreach (var iprop in iprops)
|
|
|
|
- if (all || sender.HasOriginalValue(iprop.Name))
|
|
|
|
- values[string.IsNullOrWhiteSpace(prefix) ? iprop.Name : prefix + "." + iprop.Name] =
|
|
|
|
- original
|
|
|
|
- ? sender.OriginalValues.ContainsKey(iprop.Name)
|
|
|
|
- ? sender.OriginalValues[iprop.Name]
|
|
|
|
- : iprop.PropertyType.GetDefault()
|
|
|
|
- : sender.UserProperties[iprop.Name];
|
|
|
|
- }
|
|
|
|
- catch (Exception e)
|
|
|
|
- {
|
|
|
|
- Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
|
|
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ return result;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
|
|
+ public static BaseObjectSnapshot<T> TakeSnapshot<T>(this T obj)
|
|
|
|
+ where T : BaseObject
|
|
|
|
+ {
|
|
|
|
+ return new BaseObjectSnapshot<T>(obj);
|
|
|
|
+ }
|
|
|
|
+
|
|
public static List<string> Compare<T>(this T sender, Dictionary<string, object> original) where T : BaseObject
|
|
public static List<string> Compare<T>(this T sender, Dictionary<string, object> original) where T : BaseObject
|
|
{
|
|
{
|
|
var result = new List<string>();
|
|
var result = new List<string>();
|