Hi,
do you have an example of doing a nested mail merge using LINQ SQL ?
thanks
Pete
Hi,
do you have an example of doing a nested mail merge using LINQ SQL ?
thanks
Pete
Hi
Thanks for your request. I created a simple code example using LINQ to XML to demonstrate the technique. You can use the same technique with LINQ to SQL:
[Test]
public void Test001()
{
// Load XML document
XDocument ordersXml = XDocument.Load(@"Test001\data.xml");
var query = from order in ordersXml.Descendants("order")
select new
{
id = (string)order.Attribute("id"),
description = (string)order.Attribute("desc"),
items = (from item in order.Descendants("item")
where (string)item.Attribute("oredrid") == (string)order.Attribute("id")
select new
{
name = (string)item.Attribute("name"),
price = (string)item.Attribute("price"),
amount = (string)item.Attribute("amount")
})
};
// Create a custom mail merge data source from the LINQ query results
MailMergeDataSource ordersDataSource = new MailMergeDataSource(query, "orders");
// Open template and execute mail merge with regions.
Document doc = new Document(@"Test001\in.doc");
doc.MailMerge.ExecuteWithRegions(ordersDataSource);
doc.Save(@"Test001\out.doc");
}
///
/// A custom mail merge data source that you implement to allow Aspose.Words
/// to mail merge data from LINQ query results into Microsoft Word documents.
///
public class MailMergeDataSource: IMailMergeDataSource
{
///
/// Creates new instance of a custom mail merge data source
///
/// Data returned from a LINQ query
public MailMergeDataSource(IEnumerable data)
{
mEnumerator = data.GetEnumerator();
}
///
/// Creates new instance of a custom mail merge data source
///
/// Data returned from a LINQ query
/// Name of the data source is only used when you perform mail merge with regions.
/// If you would like to use simple mail merge then use constructor with one parameter.
public MailMergeDataSource(IEnumerable data, string tableName)
{
mEnumerator = data.GetEnumerator();
// Name of the data source is needed when you perform mail merge with regions
mTableName = tableName;
}
///
/// Aspose.Words call this to get a value for every data field.
///
public bool GetValue(string fieldName, out object fieldValue)
{
fieldValue = GetPropertyValue(fieldName);
return (fieldValue != null);
}
///
/// Aspose.Words calls this method when nested regions is encountered.
///
public IMailMergeDataSource GetChildDataSource(string tableName)
{
// If property contains enumerable data we will returr mail merge datasource for these data.
object nestedData = GetPropertyValue(tableName);
if (nestedData is IEnumerable)
return new MailMergeDataSource((IEnumerable) nestedData);
return null;
}
///
/// Moves to the next record in the collection.
///
public bool MoveNext()
{
// Move enumerator to next record
bool hasNexeRecord = mEnumerator.MoveNext();
if (hasNexeRecord)
mCurrentObject = mEnumerator.Current;
return hasNexeRecord;
}
///
/// The name of the data source. Used by Aspose.Words only when executing mail merge with repeatable regions.
///
public string TableName
{
get
{
return mTableName;
}
}
private object GetPropertyValue(string propertyName)
{
object propertyValue = null;
// Get type of current record
Type curentRecordType = mCurrentObject.GetType();
// Use reflection to get property by name and its value
PropertyInfo property = curentRecordType.GetProperty(propertyName);
if (property != null)
propertyValue = property.GetValue(mCurrentObject, null) ?? string.Empty;
return propertyValue;
}
private IEnumerator mEnumerator;
private object mCurrentObject;
private string mTableName = string.Empty;
}
Hope this helps. Please let me know if you need more assistance, I will be glad to help you.
Best regards,
Many thanks Alexey!
Pete