rewrite QB mapping to use fluent api
This commit is contained in:
parent
f1fcdb9e38
commit
d67c7546ab
@ -1,16 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace COA.EnterpriseServices.DataAccess.QuickBase
|
||||
namespace COA.EnterpriseServices.DataAccess.QuickBase
|
||||
{
|
||||
internal class FieldMap
|
||||
{
|
||||
internal Type ItemType { get; set; }
|
||||
internal string PropertyName { get; set; }
|
||||
internal int FieldId { get; set; }
|
||||
}
|
||||
|
||||
internal class TableMap<TEntity, TEnumFieldMap>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,149 +0,0 @@
|
||||
using COA.Common;
|
||||
using COA.EnterpriseServices.DataAccess.Entities;
|
||||
using COA.PartnerApis.QuickBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace COA.EnterpriseServices.DataAccess.QuickBase
|
||||
{
|
||||
internal static class FieldMapRegistry
|
||||
{
|
||||
private static readonly ICollection<FieldMap> fieldRegistry = new List<FieldMap>();
|
||||
private static readonly IDictionary<Type, string> tableRegistry = new Dictionary<Type, string>();
|
||||
|
||||
static FieldMapRegistry()
|
||||
{
|
||||
AddTable<Creditor, CreditorsFieldMap>()
|
||||
.WithDefaults()
|
||||
.WithProperty(c => c.Status, CreditorsFieldMap.CreditorStatus)
|
||||
.WithProperty(c => c.ClientFirstName, CreditorsFieldMap.ClientFirstName)
|
||||
.WithProperty(c => c.ClientLastName, CreditorsFieldMap.ClientLastName)
|
||||
.WithProperty(c => c.CurrentCreditorProfileId, CreditorsFieldMap.RelatedCurrentCreditorPrimary)
|
||||
.WithProperty(c => c.OriginalCreditorProfileId, CreditorsFieldMap.RelatedOriginalCreditor)
|
||||
.WithProperty(c => c.AccountNumber, CreditorsFieldMap.AccountNum);
|
||||
|
||||
AddTable<Entities.Client, ClientFieldMap>()
|
||||
.WithDefaults()
|
||||
.WithProperty(c => c.FirstName, ClientFieldMap.FirstName)
|
||||
.WithProperty(c => c.LastName, ClientFieldMap.LastName)
|
||||
.WithProperty(c => c.Email, ClientFieldMap.ClientPrimaryEmail)
|
||||
.WithProperty(c => c.Phone, ClientFieldMap.ClientPrimaryPhone);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a table mapping for a QuickBase field map
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <typeparam name="TEnumFieldMap"></typeparam>
|
||||
/// <returns></returns>
|
||||
private static TableMap<TEntity, TEnumFieldMap> AddTable<TEntity, TEnumFieldMap>() where TEntity : IRecord
|
||||
{
|
||||
var tableNameAttribute = typeof(TEnumFieldMap).GetCustomAttribute<QuickBaseNameAttribute>();
|
||||
|
||||
if (tableNameAttribute != null)
|
||||
{
|
||||
tableRegistry.Add(typeof(TEntity), tableNameAttribute.Name);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds default property mappings for common fields
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <typeparam name="TEnumFieldMap"></typeparam>
|
||||
/// <param name="table"></param>
|
||||
/// <returns></returns>
|
||||
internal static TableMap<TEntity, TEnumFieldMap> WithDefaults<TEntity, TEnumFieldMap>(this TableMap<TEntity, TEnumFieldMap> table) where TEntity : IRecord where TEnumFieldMap : Enum
|
||||
{
|
||||
fieldRegistry.Add(new FieldMap
|
||||
{
|
||||
ItemType = typeof(TEntity),
|
||||
PropertyName = nameof(IRecord.Id),
|
||||
FieldId = PartnerApis.QuickBase.Constants.RecordIdFieldId
|
||||
});
|
||||
|
||||
fieldRegistry.Add(new FieldMap
|
||||
{
|
||||
ItemType = typeof(TEntity),
|
||||
PropertyName = nameof(IRecord.Created),
|
||||
FieldId = PartnerApis.QuickBase.Constants.DateCreatedFieldId
|
||||
});
|
||||
|
||||
fieldRegistry.Add(new FieldMap
|
||||
{
|
||||
ItemType = typeof(TEntity),
|
||||
PropertyName = nameof(IRecord.Modified),
|
||||
FieldId = PartnerApis.QuickBase.Constants.DateModifiedFieldId
|
||||
});
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a propert mapping for an entity property
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <typeparam name="TEnumFieldMap"></typeparam>
|
||||
/// <param name="table"></param>
|
||||
/// <param name="property"></param>
|
||||
/// <param name="field"></param>
|
||||
/// <returns></returns>
|
||||
internal static TableMap<TEntity, TEnumFieldMap> WithProperty<TEntity, TEnumFieldMap>(this TableMap<TEntity, TEnumFieldMap> table, Expression<Func<TEntity, object>> property, TEnumFieldMap field)
|
||||
{
|
||||
if (property.Body is MemberExpression memberExpression)
|
||||
{
|
||||
fieldRegistry.Add(new FieldMap
|
||||
{
|
||||
ItemType = memberExpression.Member.DeclaringType,
|
||||
PropertyName = memberExpression.Member.Name,
|
||||
FieldId = field.To<int>()
|
||||
});
|
||||
}
|
||||
else if (property.Body is UnaryExpression unaryExpression && unaryExpression.Operand is MemberExpression unaryMemberExpression)
|
||||
{
|
||||
fieldRegistry.Add(new FieldMap
|
||||
{
|
||||
ItemType = unaryMemberExpression.Member.DeclaringType,
|
||||
PropertyName = unaryMemberExpression.Member.Name,
|
||||
FieldId = field.To<int>()
|
||||
});
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
internal static int? GetFieldId(PropertyInfo info)
|
||||
{
|
||||
var map = fieldRegistry.FirstOrDefault(m => m.ItemType == info.DeclaringType && m.PropertyName == info.Name);
|
||||
|
||||
return map != null ? map.FieldId : default;
|
||||
}
|
||||
|
||||
internal static QuickBaseRecordContext GetTableContext(object item)
|
||||
{
|
||||
var context = new QuickBaseRecordContext();
|
||||
var itemType = item.GetType();
|
||||
var properties = itemType.GetProperties();
|
||||
|
||||
context.Table = tableRegistry.FirstOrDefault(r => r.Key == itemType).Value;
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
var fieldId = GetFieldId(property);
|
||||
var value = property.GetValue(item);
|
||||
|
||||
if (fieldId != null)
|
||||
{
|
||||
context.FieldIds.Add(new KeyValuePair<int, object>(fieldId.Value, value));
|
||||
}
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
}
|
||||
}
|
@ -16,18 +16,18 @@ namespace COA.EnterpriseServices.DataAccess.QuickBase
|
||||
|
||||
public bool Add(T item)
|
||||
{
|
||||
var fieldData = FieldMapRegistry.GetTableContext(item);
|
||||
var record = RecordMapRegistry.GetRecord(item);
|
||||
|
||||
var result = client.AddRecord(fieldData.Table, fieldData.FieldIds);
|
||||
var result = client.AddRecord(record.Table, record.FieldIds);
|
||||
|
||||
return result.Success;
|
||||
}
|
||||
|
||||
public bool Update(T item)
|
||||
{
|
||||
var fieldData = FieldMapRegistry.GetTableContext(item);
|
||||
var record = RecordMapRegistry.GetRecord(item);
|
||||
|
||||
var result = client.EditRecord(item.Id, fieldData.Table, fieldData.FieldIds);
|
||||
var result = client.EditRecord(item.Id, record.Table, record.FieldIds);
|
||||
|
||||
return result.Success;
|
||||
}
|
||||
|
@ -2,7 +2,10 @@
|
||||
|
||||
namespace COA.EnterpriseServices.DataAccess.QuickBase
|
||||
{
|
||||
internal class QuickBaseRecordContext
|
||||
/// <summary>
|
||||
/// Represents record data to be used in the QuickBase API
|
||||
/// </summary>
|
||||
internal class Record
|
||||
{
|
||||
internal string Table { get; set; }
|
||||
internal IDictionary<int, object> FieldIds { get; set; } = new Dictionary<int, object>();
|
92
COA.EnterpriseServices.DataAccess.QuickBase/RecordMap.cs
Normal file
92
COA.EnterpriseServices.DataAccess.QuickBase/RecordMap.cs
Normal file
@ -0,0 +1,92 @@
|
||||
using COA.Common;
|
||||
using COA.PartnerApis.QuickBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace COA.EnterpriseServices.DataAccess.QuickBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a map between a CLR type, its QuickBase table, and fields
|
||||
/// </summary>
|
||||
internal abstract class RecordMap
|
||||
{
|
||||
internal Type ItemType { get; set; }
|
||||
internal string Table { get; set; }
|
||||
internal ICollection<FieldMap> FieldMaps { get; } = new List<FieldMap>();
|
||||
}
|
||||
|
||||
internal class RecordMap<TEntity, TEnumFieldMap> : RecordMap where TEntity : IRecord where TEnumFieldMap : Enum
|
||||
{
|
||||
internal RecordMap()
|
||||
{
|
||||
ItemType = typeof(TEntity);
|
||||
|
||||
var tableNameAttribute = typeof(TEnumFieldMap).GetCustomAttribute<QuickBaseNameAttribute>();
|
||||
|
||||
if (tableNameAttribute != null)
|
||||
{
|
||||
Table = tableNameAttribute.Name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a propery mapping for an entity property
|
||||
/// </summary>
|
||||
/// <param name="property"></param>
|
||||
/// <param name="field"></param>
|
||||
/// <returns></returns>
|
||||
internal RecordMap<TEntity, TEnumFieldMap> WithProperty(Expression<Func<TEntity, object>> property, TEnumFieldMap field)
|
||||
{
|
||||
if (property.Body is MemberExpression memberExpression)
|
||||
{
|
||||
FieldMaps.Add(new FieldMap
|
||||
{
|
||||
PropertyName = memberExpression.Member.Name,
|
||||
FieldId = field.To<int>()
|
||||
});
|
||||
}
|
||||
else if (property.Body is UnaryExpression unaryExpression && unaryExpression.Operand is MemberExpression unaryMemberExpression)
|
||||
{
|
||||
FieldMaps.Add(new FieldMap
|
||||
{
|
||||
PropertyName = unaryMemberExpression.Member.Name,
|
||||
FieldId = field.To<int>()
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds default property mappings for common entity fields
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <typeparam name="TEnumFieldMap"></typeparam>
|
||||
/// <param name="table"></param>
|
||||
/// <returns></returns>
|
||||
internal RecordMap<TEntity, TEnumFieldMap> WithDefaults()
|
||||
{
|
||||
FieldMaps.Add(new FieldMap
|
||||
{
|
||||
PropertyName = nameof(IRecord.Id),
|
||||
FieldId = PartnerApis.QuickBase.Constants.RecordIdFieldId
|
||||
});
|
||||
|
||||
FieldMaps.Add(new FieldMap
|
||||
{
|
||||
PropertyName = nameof(IRecord.Created),
|
||||
FieldId = PartnerApis.QuickBase.Constants.DateCreatedFieldId
|
||||
});
|
||||
|
||||
FieldMaps.Add(new FieldMap
|
||||
{
|
||||
PropertyName = nameof(IRecord.Modified),
|
||||
FieldId = PartnerApis.QuickBase.Constants.DateModifiedFieldId
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
using COA.EnterpriseServices.DataAccess.Entities;
|
||||
using COA.PartnerApis.QuickBase;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace COA.EnterpriseServices.DataAccess.QuickBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Maintains a list of entity types and property mappings to QuickBase fields
|
||||
/// </summary>
|
||||
internal static class RecordMapRegistry
|
||||
{
|
||||
private static readonly ICollection<RecordMap> recordMaps = new List<RecordMap>();
|
||||
|
||||
static RecordMapRegistry()
|
||||
{
|
||||
#region Creditor
|
||||
|
||||
recordMaps.Add(new RecordMap<Creditor, CreditorsFieldMap>()
|
||||
.WithDefaults()
|
||||
.WithProperty(c => c.ClientFirstName, CreditorsFieldMap.ClientFirstName)
|
||||
.WithProperty(c => c.ClientFirstName, CreditorsFieldMap.ClientFirstName)
|
||||
.WithProperty(c => c.ClientLastName, CreditorsFieldMap.ClientLastName)
|
||||
.WithProperty(c => c.CurrentCreditorProfileId, CreditorsFieldMap.RelatedCurrentCreditorPrimary)
|
||||
.WithProperty(c => c.OriginalCreditorProfileId, CreditorsFieldMap.RelatedOriginalCreditor)
|
||||
.WithProperty(c => c.Status, CreditorsFieldMap.CreditorStatus)
|
||||
.WithProperty(c => c.AccountNumber, CreditorsFieldMap.AccountNum));
|
||||
|
||||
#endregion
|
||||
|
||||
#region Client
|
||||
|
||||
recordMaps.Add(new RecordMap<Entities.Client, ClientFieldMap>()
|
||||
.WithDefaults()
|
||||
.WithProperty(c => c.FirstName, ClientFieldMap.FirstName)
|
||||
.WithProperty(c => c.LastName, ClientFieldMap.LastName)
|
||||
.WithProperty(c => c.Email, ClientFieldMap.ClientPrimaryEmail)
|
||||
.WithProperty(c => c.Phone, ClientFieldMap.ClientPrimaryPhone)
|
||||
.WithProperty(c => c.Address, ClientFieldMap.Address1));
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
internal static Record GetRecord(object item)
|
||||
{
|
||||
var data = new Record();
|
||||
var itemType = item.GetType();
|
||||
var properties = itemType.GetProperties();
|
||||
var map = recordMaps.FirstOrDefault(r => r.ItemType == itemType);
|
||||
|
||||
data.Table = map.Table;
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
var fieldMap = map.FieldMaps.FirstOrDefault(f => f.PropertyName == property.Name);
|
||||
|
||||
if (fieldMap != null)
|
||||
{
|
||||
var value = property.GetValue(item);
|
||||
|
||||
data.FieldIds.Add(new KeyValuePair<int, object>(fieldMap.FieldId, value));
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user