Buduję interfejs API wokół wywołania usługi internetowej za pomocą wyrażeń, aby umożliwić programistom określenie zapytania i wyrażenie ExpressionVisitor przekształcić wyrażenie w łańcuch zapytania. Żądanie to XML z określonym elementem zawierającym ciąg zapytania.Jak skompilować wyrażenie do rzeczywistego wyniku?
Na przykład, mogę zrobić coś takiego, które będzie pobierać wszystkie rachunki sprawdzanie z nazwą banku banku 1 lub banku 2:
"BANKNAME = 'Bank 1' lub BANKNAME = 'Bank 2'"
Usługa internetowa może obsługiwać znacznie bardziej skomplikowane zapytania, ale na razie pozostanę z tym.
Więc mam klasy CheckingAccount:
[IntacctObject("checkingaccount")]
public class CheckingAccount : Entity
{
[IntacctElement("bankaccountid")]
public string Id { get; set; }
[IntacctElement("bankname")]
public string BankName { get; set; }
}
i ExpressionVisitor, którego głównym zadaniem jest konwertowanie wyrażenie takiego:
Expression> expression = ca => ca.BankName == "Bank 1" || ca.BankName == "Bank 2"
do zapytania: „BANKNAME = 'banku 1' lub nazwa banku = "Bank 2" "
To nie jest takie trudne. Gdzie wszystko zaczyna się załamać się kiedy wprowadzać zmienne lokalne:
var account = new CheckingAccount { BankName = "Bank 1" };
string bankName = "Bank 2";
Expression> expression = ca => ca.BankName == account.BankName || ca.BankName == bankName;
wiem, jak radzić sobie z prostym zmiennej lokalnej (czyli ciąg BANKNAME = „Bank 2”.), Ale do czynienia z innego rodzaju (var account = new CheckingAccount {BankName = "Bank 1"}) jest znacznie bardziej złożony.
Pod koniec dnia są to wielkie problemy, które muszę wymyślić, jak sobie z tym poradzić. Wiem, że są o wiele bardziej skomplikowane scenariusze, ale w tej chwili nie interesuję się nimi.
Oto mój gość wyrażenie (proszę zwrócić uwagę na ogólną presję na metodzie CreateFilter):
internal class IntacctWebService30ExpressionVisitor : ExpressionVisitor
{
private readonly List _Filters = new List();
private IntacctWebServicev30SimpleQueryFilter _CurrentSimpleFilter;
private IntacctWebServicev30ComplexQueryFilter _CurrentComplexFilter;
private MemberExpression _CurrentMemberExpression;
public string CreateFilter(Expression> expression) where TEntity : Entity
{
Visit(expression);
string filter = string.Join(string.Empty, _Filters.Select(f => f.ToString()).ToArray());
return filter;
}
protected override Expression VisitBinary(BinaryExpression node)
{
switch (node.NodeType)
{
case ExpressionType.AndAlso:
case ExpressionType.OrElse:
_CurrentComplexFilter = new IntacctWebServicev30ComplexQueryFilter { ExpressionType = node.NodeType };
break;
case ExpressionType.Equal:
case ExpressionType.GreaterThan:
case ExpressionType.GreaterThanOrEqual:
case ExpressionType.LessThan:
case ExpressionType.LessThanOrEqual:
case ExpressionType.NotEqual:
_CurrentSimpleFilter = new IntacctWebServicev30SimpleQueryFilter { ExpressionType = node.NodeType };
break;
}
return base.VisitBinary(node);
}
protected override Expression VisitMember(MemberExpression node)
{
var attr = node.Member.GetAttribute();
if (attr != null)
_CurrentSimpleFilter.FieldName = attr.FieldName;
else
_CurrentMemberExpression = node;
return base.VisitMember(node);
}
protected override Expression VisitConstant(ConstantExpression node)
{
object value = Expression.Lambda>(node).Compile().Invoke();
string fieldValue = extraxtFieldValue(value, node);
_CurrentSimpleFilter.FieldValue = fieldValue;
if (_CurrentComplexFilter != null)
{
if (_CurrentComplexFilter.Left == null)
{
_CurrentComplexFilter.Left = _CurrentSimpleFilter;
}
else if (_CurrentComplexFilter.Right == null)
{
_CurrentComplexFilter.Right = _CurrentSimpleFilter;
_Filters.Add(_CurrentComplexFilter);
}
else
throw new InvalidOperationException();
}
else
{
_Filters.Add(_CurrentSimpleFilter);
}
return base.VisitConstant(node);
}
private string extraxtFieldValue(object value)
{
string fieldValue;
if (value is DateTime)
fieldValue = ((DateTime)value).ToString("yyyy-MM-dd");
else if (value is string)
fieldValue = value.ToString();
else if (value.GetType().IsEnum)
{
throw new NotImplementedException();
}
else
{
// Not sure if this is the best way to do this or not but can't figure out how
// else to get a variable value.
// If we are here then we are dealing with a property, field, or variable.
// This means we must extract the value from the object.
// In order to do this we will rely on _CurrentMemberExpression
if (_CurrentMemberExpression.Member.MemberType == MemberTypes.Property)
{
fieldValue = value.GetType().GetProperty(_CurrentMemberExpression.Member.Name).GetValue(value, null).ToString();
}
else if (_CurrentMemberExpression.Member.MemberType == MemberTypes.Field)
{
fieldValue = value.GetType().GetFields().First().GetValue(value).ToString();
}
else
{
throw new InvalidOperationException();
}
}
return fieldValue;
}
}
Proszę dać mi znać, jeśli chcesz już więcej szczegółów ....
Dzięki
Czy Twoje filtry zawsze będą Entity.Property dla lewej strony op binarnej? – MerickOWA
Będą to właściwości lub pola. – devlife
Widzę, że przyjąłeś moją odpowiedź na inne pytanie, czy moja odpowiedź była wystarczająco jasna, abyś mógł zintegrować swoje klasy QueryFilter? – MerickOWA