Изменение сводной таблицы Excel с помощью набора записей и обновления: исключение

Я на грани своего ума и потерял целый день, пытаясь сделать что-то, что не должно быть таким сложным.

У меня есть набор записей, который был возвращен из запроса Sybase. Этот набор записей использовался для создания сводной таблицы в Excel. Все идет нормально. Я хочу изменить значение в сводной таблице, и для этого я использую новое значение для обновления определенных записей в наборе записей. Я могу выполнить обновление в RS без каких-либо проблем, и значения сохраняются в RS в следующий раз, когда я перебираю его.

Проблема в том, что значения не отражаются в сводной таблице. Я пытался:

  • pivotTable.Refresh();
    • COMException: RefreshTable method of PivotTable class failed
  • pivotTable.PivotCache().Refresh();
    • ComException: Exception from HRESULT: 0x800A03EC
  • pivotTable.Update();
    • No exception but the changes are not reflected in the pivot table

Я также попытался клонировать набор записей и создать из него совершенно новую сводную таблицу, но хотя в Recordset есть данные, PivotCache.RecordCount равно 0

Код:

var app = ExcelAppHelper.GetExcelApp();
if (app.ActiveCell == null || app.ActiveCell.PivotTable == null)
    return;

PivotTable pivotTable = app.ActiveCell.PivotTable;
var rs = (Recordset)pivotTable.PivotCache().Recordset;
rs.MoveFirst();

s_lastSelectedPivotTree = new PivotFilterTree();
RecalculateSelectedValues(vmMain);

while (!rs.EOF)
{
    if (s_lastSelectedPivotTree.Contains(rs.Fields))
    {
        foreach (var dataFieldName in s_lastSelectedDataFields)
        {
            // update the values in the RS
            rs.Fields[dataFieldName].Value = newValue;
        }

        // commit the modifications into the RS
        rs.Update(Type.Missing, Type.Missing);
    }
    rs.MoveNext();
}
rs.MoveFirst();

// here is the magic line that will show me the updated pivot table
pivotTable.Update();

Кто-нибудь знает, как это сделать? Измените набор записей, затем «обновите» сводную таблицу, чтобы пересчитать сводную таблицу на основе набора записей.

Спасибо, Шон.


person sean.net    schedule 09.10.2012    source источник


Ответы (1)


Ну, я решил это. Кажется, что после того, как Recordset был «потреблен» PivotTable, вы можете изменить его как хотите, просто он не будет обновляться в Excel. Несмотря на то, что Recordset содержит данные, обновление очистит PivotTable и приведет к потере данных.

Обходной путь? Создайте глубокую копию (Recordset.Clone() не будет работать) Recordset, прежде чем передать ее PivotTable, а затем каждый раз, когда вы хотите изменить значение в ней, измените «чистую» копию, сделайте новую копию и передайте скопируйте в PivotTable, чтобы использовать его. Затем обновите файл PivotTable.

        var newRS = RecordsetDeepCopy(oldRS);

        newRS.MoveFirst();
        oldRS.MoveFirst();
        while (!newRS.EOF)
        {
            if (s_lastSelectedPivotTree.Contains(newRS.Fields))
            {
                // set the new value in the selected data fields
                foreach (var dataFieldName in s_lastSelectedDataFields)
                {
                    oldRS.Fields[dataFieldName].Value = val;
                    newRS.Fields[dataFieldName].Value = val;
                }

                newRS.Update(Type.Missing, Type.Missing);
                oldRS.Update(Type.Missing, Type.Missing);
            }
            newRS.MoveNext();
            oldRS.MoveNext();
        }

        newRS.MoveFirst();
        oldRS.MoveFirst();

        pivotCache.Recordset = newRS;
        pivotCache.Refresh();

И метод глубокого копирования набора записей (нелегко найти на С# в Интернете...)

private static Recordset RecordsetDeepCopy(Recordset src)
{
    var clone = new Recordset();
    int count = src.Fields.Count;
    var names = new object[count];
    int i = 0;

    foreach (ADODB.Field field in src.Fields)
    {
        names[i++] = field.Name;
        var attr = (FieldAttributeEnum)field.Attributes;
        clone.Fields._Append(field.Name, field.Type, field.DefinedSize, attr);
    }

    clone.Open(Missing.Value, Missing.Value, CursorTypeEnum.adOpenUnspecified, LockTypeEnum.adLockUnspecified, 0);

    src.MoveFirst();

    while (!src.EOF)
    {
        var values = new object[count];
        i = 0;
        foreach (ADODB.Field field in src.Fields)
        {
            values[i++] = field.Value;
        }

        clone.AddNew(names, values);
        src.MoveNext();
    }

    clone.Update(Missing.Value, Missing.Value);
    return clone;
}

Надеюсь, это избавит других от головной боли...

Шон

person sean.net    schedule 12.10.2012