You could do with a new predicate but as an expression already is able to refer to 2 fields, why not use that instead?
So as you requested some help, here we go.
Let's call this expression the ConcatenateFieldName expression. I'll re-use the Expression.cs sourcecode, and put it in a new class. You can then place this class in your own project.
[Serializable]
public class ConcatenateFieldNameExpression: IExpression, ISerializable
{
#region Class Member Declarations
private IExpressionElement _leftOperand, _rightOperand;
private ExOp _operator;
[NonSerialized]
private List<IDataParameter> _parameters;
[NonSerialized]
private IDbSpecificCreator _creator;
#endregion
#region Constructors
public ConcatenateFieldNameExpression()
{
InitClass();
_leftOperand = null;
_rightOperand = null;
_operator = ExOp.None;
}
public ConcatenateFieldNameExpression(IEntityFieldCore leftOperand, ExOp operatorToUse, IEntityFieldCore rightOperand)
{
InitClass();
_leftOperand = new ExpressionFieldElement( ExpressionElementType.Field, leftOperand, leftOperand as IFieldPersistenceInfo );
_rightOperand = new ExpressionFieldElement( ExpressionElementType.Field, rightOperand, rightOperand as IFieldPersistenceInfo );
_operator = operatorToUse;
}
protected ConcatenateFieldNameExpression(SerializationInfo info, StreamingContext context)
{
InitClass();
_leftOperand = (IExpressionElement)info.GetValue("_leftOperand", typeof(IExpressionElement));
_rightOperand = (IExpressionElement)info.GetValue("_rightOperand", typeof(IExpressionElement));
_operator = (ExOp)info.GetValue("_operator", typeof(ExOp));
}
#endregion
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("_leftOperand", _leftOperand, typeof(IExpressionElement));
info.AddValue("_rightOperand", _rightOperand, typeof(IExpressionElement));
info.AddValue("_operator", _operator, typeof(ExOp));
}
public string ToQueryText(ref int uniqueMarker)
{
return ToQueryText(ref uniqueMarker, false);
}
public virtual string ToQueryText(ref int uniqueMarker, bool inHavingClause)
{
if(_creator==null)
{
throw new System.ApplicationException("DatabaseSpecificCreator object not set. Cannot create query part.");
}
StringBuilder queryText = new StringBuilder(128);
_parameters.Clear();
OperandToText(ref queryText, _leftOperand, ref uniqueMarker, true, inHavingClause);
switch(_operator)
{
case ExOp.Add:
queryText.Append(" + ");
break;
case ExOp.Or:
queryText.Append(" || ");
break;
}
OperandToText(ref queryText, _rightOperand, ref uniqueMarker, false, inHavingClause);
return queryText.ToString();
}
private void OperandToText(ref StringBuilder queryText, IExpressionElement operand, ref int uniqueMarker, bool isLeftOperand, bool inHavingClause)
{
IExpressionFieldElement fieldElement = (IExpressionFieldElement)operand;
IEntityFieldCore fieldCore = (IEntityFieldCore)fieldElement.Contents;
queryText.AppendFormat(null, "{0}", _creator.CreateFieldName(fieldCore, fieldElement.PersistenceInfo, fieldCore.Name, fieldCore.ObjectAlias,
ref uniqueMarker, inHavingClause));
if(fieldCore.ExpressionToApply!=null)
{
_parameters.AddRange(fieldCore.ExpressionToApply.Parameters);
}
}
private void InitClass()
{
_parameters = new List<IDataParameter>();
_creator = null;
}
#region Class Property Declarations
public List<IDataParameter> Parameters
{
get { return _parameters;}
}
public IDbSpecificCreator DatabaseSpecificCreator
{
get { return _creator;}
set {_creator = value;}
}
public IExpressionElement LeftOperand
{
get { return _leftOperand;}
}
public IExpressionElement RightOperand
{
get { return _rightOperand;}
}
public ExOp Operator
{
get { return _operator;}
}
#endregion
}
Most code is comments, so the code is pretty small and straight forward.
You then use it like:
IEntityField contatenatedFields = CustomersFields.CustomerId.SetExpression(new ConcatenateFieldNameExpression(CustomersFields.CompanyName, ExOp.Or, CustomersFields.ContactName));
Which will result in a field || field result.
If you're on sqlserver, use ExOp.Add.