private void OnColumnValueChanged(DataRow row, DataColumn col, XmlBoundElement rowElement)
{
if (IsNotMapped(col))
{
goto lblDoNestedRelationSync;
}
object value = row[col];
if (col.ColumnMapping == MappingType.SimpleContent && Convert.IsDBNull(value) && !rowElement.IsFoliated)
{
ForceFoliation(rowElement, ElementState.WeakFoliation);
}
else
{
// no need to sync if not foliated
if (!IsFoliated(rowElement))
{
#if DEBUG
// If the new value is null, we should be already foliated if there is a DataPointer that points to the column
// (see OnRowChanging, case DataRowAction.Change)
if (Convert.IsDBNull(row[col, DataRowVersion.Current]))
{
try
{
if (_pointers.Count > 0)
{
object pointer = null;
foreach (DictionaryEntry entry in _pointers)
{
pointer = entry.Value;
Debug.Assert((pointer != null) && !((IXmlDataVirtualNode)pointer).IsOnColumn(col));
}
}
}
catch (Exception e) when (Data.Common.ADP.IsCatchableExceptionType(e))
{
// We may get an exception if we are in foreach and a new pointer has been added to this.pointers. When this happens, we will skip this check and ignore the exceptions
}
}
#endif
goto lblDoNestedRelationSync;
}
}
if (IsTextOnly(col))
{
if (Convert.IsDBNull(value))
{
value = string.Empty;
//make sure that rowElement has Attribute xsi:nil and its value is true
XmlAttribute attr = rowElement.GetAttributeNode(XSI_NIL);
if (attr == null)
{
attr = CreateAttribute(XSI, Keywords.XSI_NIL, Keywords.XSINS);
attr.Value = Keywords.TRUE;
rowElement.SetAttributeNode(attr);
_bHasXSINIL = true;
}
else
attr.Value = Keywords.TRUE;
}
else
{
//make sure that if rowElement has Attribute xsi:nil, its value is false
XmlAttribute attr = rowElement.GetAttributeNode(XSI_NIL);
if (attr != null)
attr.Value = Keywords.FALSE;
}
ReplaceInitialChildText(rowElement, col.ConvertObjectToXml(value));
goto lblDoNestedRelationSync;
}
// update the attribute that maps to the column
bool fFound = false;
// Find the field node and set it's value
if (col.ColumnMapping == MappingType.Attribute)
{
foreach (XmlAttribute attr in rowElement.Attributes)
{
if (attr.LocalName == col.EncodedColumnName && attr.NamespaceURI == col.Namespace)
{
if (Convert.IsDBNull(value))
{
attr.OwnerElement.Attributes.Remove(attr);
}
else
{
attr.Value = col.ConvertObjectToXml(value);
}
fFound = true;
break;
}
}
// create new attribute if we didn't find one.
if (!fFound && !Convert.IsDBNull(value))
{
rowElement.SetAttribute(col.EncodedColumnName, col.Namespace, col.ConvertObjectToXml(value));
}
}
else
{
// update elements that map to the column...
RegionIterator iter = new RegionIterator(rowElement);
bool fMore = iter.Next();
while (fMore)
{
if (iter.CurrentNode.NodeType == XmlNodeType.Element)
{
XmlElement e = (XmlElement)iter.CurrentNode;
Debug.Assert(e != null);
//we should skip the subregion
XmlBoundElement be = e as XmlBoundElement;
if (be != null && be.Row != null)
{
fMore = iter.NextRight(); //skip over the sub-region
continue;
}
if (e.LocalName == col.EncodedColumnName && e.NamespaceURI == col.Namespace)
{
fFound = true;
if (Convert.IsDBNull(value))
{
PromoteNonValueChildren(e);
fMore = iter.NextRight();
e.ParentNode.RemoveChild(e);
// keep looking for more matching elements
continue;
}
else
{
ReplaceInitialChildText(e, col.ConvertObjectToXml(value));
//make sure that if the Element has Attribute xsi:nil, its value is false
XmlAttribute attr = e.GetAttributeNode(XSI_NIL);
if (attr != null)
attr.Value = Keywords.FALSE;
// no need to look any further.
goto lblDoNestedRelationSync;
}
}
}
fMore = iter.Next();
}
// create new element if we didn't find one.
if (!fFound && !Convert.IsDBNull(value))
{
XmlElement newElem = new XmlBoundElement(string.Empty, col.EncodedColumnName, col.Namespace, this);
newElem.AppendChild(CreateTextNode(col.ConvertObjectToXml(value)));
XmlNode elemBefore = GetColumnInsertAfterLocation(row, col, rowElement);
if (elemBefore != null)
{
rowElement.InsertAfter(newElem, elemBefore);
}
else if (rowElement.FirstChild != null)
{
rowElement.InsertBefore(newElem, rowElement.FirstChild);
}
else
{
rowElement.AppendChild(newElem);
}
}
}
lblDoNestedRelationSync:
// Change the XML to conform to the (potentially) change in parent nested relation
DataRelation relation = GetNestedParentRelation(row);
if (relation != null)
{
Debug.Assert(relation.ChildTable == row.Table);
if (relation.ChildKey.ContainsColumn(col))
OnNestedParentChange(row, rowElement, col);
}
}