private void SynchronizeRowFromRowElementEx(XmlBoundElement rowElement, ArrayList rowElemList) { Debug.Assert(rowElement != null); Debug.Assert(rowElement.Row != null); Debug.Assert(DataSet.EnforceConstraints == false); DataRow row = rowElement.Row; Debug.Assert(row != null); DataTable table = row.Table; Hashtable foundColumns = new Hashtable(); string xsi_attrVal = string.Empty; RegionIterator iter = new RegionIterator(rowElement); bool fMore; // If present, fill up the TextOnly column DataColumn column = GetTextOnlyColumn(row); if (column != null) { foundColumns[column] = column; string value; fMore = iter.NextInitialTextLikeNodes(out value); if (value.Length == 0 && (((xsi_attrVal = rowElement.GetAttribute(XSI_NIL)) == "1") || xsi_attrVal == "true")) row[column] = DBNull.Value; else SetRowValueFromXmlText(row, column, value); } else fMore = iter.Next(); // Fill up the columns mapped to an element while (fMore) { XmlElement e = iter.CurrentNode as XmlElement; if (e == null) { fMore = iter.Next(); continue; } XmlBoundElement be = e as XmlBoundElement; if (be != null && be.Row != null) { if (rowElemList != null) rowElemList.Add(e); // Skip over sub-regions fMore = iter.NextRight(); continue; } DataColumn c = _mapper.GetColumnSchemaForNode(rowElement, e); if (c != null) { Debug.Assert(c.Table == row.Table); if (foundColumns[c] == null) { foundColumns[c] = c; string value; fMore = iter.NextInitialTextLikeNodes(out value); if (value.Length == 0 && (((xsi_attrVal = e.GetAttribute(XSI_NIL)) == "1") || xsi_attrVal == "true")) row[c] = DBNull.Value; else SetRowValueFromXmlText(row, c, value); continue; } } fMore = iter.Next(); } // // Walk the attributes to find attributes that map to columns. // foreach (XmlAttribute attr in rowElement.Attributes) { DataColumn c = _mapper.GetColumnSchemaForNode(rowElement, attr); if (c != null) { if (foundColumns[c] == null) { foundColumns[c] = c; SetRowValueFromXmlText(row, c, attr.Value); } } } // Null all columns values that aren't represented in the tree foreach (DataColumn c in row.Table.Columns) { if (foundColumns[c] == null && !IsNotMapped(c)) { if (!c.AutoIncrement) SetRowValueToNull(row, c); else c.Init(row._tempRecord); } } }
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); } }