Столбцы DataTable устанавливаются как ReadOnly при использовании объединения - PullRequest
0 голосов
/ 01 ноября 2018

Я пытаюсь получить DataTable и обновить его позже в моей программе, однако я получаю System.Exception при попытке изменить один из моих столбцов (IsUsed). Ошибка чтения: «Столбец IsUsed читается только'. Что верно, для столбца в DataTable свойство ReadOnly имеет значение true.

Вот мой код C #, который генерирует мой SQL:

public IgnoredPositionSet GetAllForReconciliation(int aReconciliationId)
{   
      SqlGenerator internalIgnoredPositionSqlGenerator = base.GetCoreSqlGenerator()
        .Select.Add(@"
          IP.SecurityId,
          IP.SecurityName,
          IP.Quantity,
          NULL AS AccountTypeName")
        .Join.Add($@"
          LEFT JOIN 
            (
              SELECT
                ReconciliationId,
                MatchId,
                SecurityId,
                SecurityName,
                SUM(QuantityTradeDate) AS Quantity
              FROM [PositionReconciliation.InternalPosition]
              GROUP BY
                ReconciliationId,
                MatchId,
                SecurityId,
                SecurityName
            ) IP
          ON IP.ReconciliationId = {ServiceTableAlias}.ReconciliationId
          AND IP.MatchId         = {ServiceTableAlias}.MatchId")
        .Where.Add("IsInternalPosition = 1");

      SqlGenerator externalIgnoredPositionSqlGenerator = GetCoreSqlGenerator()
        .Select.Add(@"
          NULL AS SecurityId,
          EP.SecurityName,
          EP.Quantity,
          AccountTypeName")
        .Join.Add($@"
          LEFT JOIN 
            (
              SELECT
                ReconciliationId,
                MatchId,
                SecurityName,
                SUM(QuantityTradeDate) AS Quantity
              FROM [PositionReconciliation.ExternalPosition]
              GROUP BY
                ReconciliationId,
                MatchId,
                SecurityName
            ) EP
          ON EP.ReconciliationId = {ServiceTableAlias}.ReconciliationId
          AND EP.MatchId         = {ServiceTableAlias}.MatchId")
        .Join.Add($@"
          LEFT JOIN
            (
              SELECT
                EP.ReconciliationId,
                EP.MatchId,
                A.AccountTypeId,
                AT.Name AS AccountTypeName
              FROM [PositionReconciliation.ExternalPosition] EP
              LEFT JOIN [Core.CustodianFund.AccountMap]      A  ON A.Id  = EP.CustodianAccountId
              LEFT JOIN [Reconciliation.Cash.AccountType]    AT ON AT.Id = A.AccountTypeId
              GROUP BY ReconciliationId, MatchId, AccountTypeId, AT.Name
            ) EPAT
          ON  EPAT.ReconciliationId = {ServiceTableAlias}.ReconciliationId
          AND EPAT.MatchId          = {ServiceTableAlias}.MatchId")
        .Where.Add("IsInternalPosition = 0");

      var internalPositions = GetEntitySet(internalIgnoredPositionSqlGenerator); //ReadOnly props are false
      var externalPositions = GetEntitySet(externalIgnoredPositionSqlGenerator); //ReadOnly props are false

      return GetEntitySet($"SELECT * FROM ({internalIgnoredPositionSqlGenerator} UNION ALL {externalIgnoredPositionSqlGenerator}) {ServiceTableAlias} WHERE {nameof(IgnoredPosition.ReconciliationId)} = {aReconciliationId}");

Результирующий SQL выглядит так:

SELECT
  SERVICE_TABLE.*,
  IP.SecurityId,
  IP.SecurityName,
  IP.Quantity,
  NULL AS AccountTypeName
FROM [PositionReconciliation.IgnoredPosition] SERVICE_TABLE
LEFT JOIN
(
SELECT
ReconciliationId,
MatchId,
SecurityId,
SecurityName,
SUM(QuantityTradeDate) AS Quantity
FROM [PositionReconciliation.InternalPosition]
GROUP BY
ReconciliationId,
MatchId,
SecurityId,
SecurityName
) IP
ON IP.ReconciliationId = SERVICE_TABLE.ReconciliationId
AND IP.MatchId         = SERVICE_TABLE.MatchId
WHERE
(IsInternalPosition = 1)
 UNION ALL
  SELECT
  SERVICE_TABLE.*,
  NULL AS SecurityId,
  EP.SecurityName,
  EP.Quantity,
  AccountTypeName
FROM [PositionReconciliation.IgnoredPosition] SERVICE_TABLE
LEFT JOIN
(
SELECT
ReconciliationId,
MatchId,
SecurityName,
SUM(QuantityTradeDate) AS Quantity
FROM [PositionReconciliation.ExternalPosition]
GROUP BY
ReconciliationId,
MatchId,
SecurityName
) EP
ON EP.ReconciliationId = SERVICE_TABLE.ReconciliationId
AND EP.MatchId         = SERVICE_TABLE.MatchId
LEFT JOIN
(
SELECT
EP.ReconciliationId,
EP.MatchId,
A.AccountTypeId,
AT.Name AS AccountTypeName
FROM [PositionReconciliation.ExternalPosition] EP
LEFT JOIN [Core.CustodianFund.AccountMap]      A  ON A.Id  = EP.CustodianAccountId
LEFT JOIN [Reconciliation.Cash.AccountType]    AT ON AT.Id = A.AccountTypeId
GROUP BY ReconciliationId, MatchId, AccountTypeId, AT.Name
) EPAT
ON  EPAT.ReconciliationId = SERVICE_TABLE.ReconciliationId
AND EPAT.MatchId          = SERVICE_TABLE.MatchId
WHERE
(IsInternalPosition = 0)

Вот код, который создает DataSet:

public DataSet GetDataSet(string                       aCommandText,
                          IEnumerable<DbDataParameter> aParameters            = null,
                          int?                         aCommandTimeoutSeconds = null,
                          bool                         aIsUpdateable          = true)
{
  var da

taSet = new DataSet
      {
        Locale             = CultureInfo.InvariantCulture,
        EnforceConstraints = false
      };

      return PerformDbOperation(new DbOperationInfo(aCommandText, aCommandTimeoutSeconds, aParameters),
                                aDbOperationInfo => 
                                {
                                  DataAdapter.SelectCommand       = aDbOperationInfo.Command;
                                  DataAdapter.MissingSchemaAction = aIsUpdateable ? MissingSchemaAction.AddWithKey : MissingSchemaAction.Add;
                                  DataAdapter.Fill(dataSet);

                                  if (dataSet.Tables.Count > 0)
                                    aDbOperationInfo.AffectedRowCount = dataSet.Tables[0].Rows.Count;

                                  return dataSet;
                                });
    }

Я играл с этим и обнаружил, что без union DataTable хорошо заполняется и устанавливает свойство ReadOnly в столбцах как ложное. Так что я знаю, что это как-то связано с профсоюзом, но я не уверен почему.

Я знаю, что этот вопрос задавался аналогичным образом ранее, но я не хочу зацикливаться на столбцах DataTable и вручную устанавливать для свойства ReadOnly значение true, я хотел бы устранить проблему на источник.

Спасибо!

ОБНОВЛЕНИЕ: Я полагаю, это потому, что столбцы классифицируются как «вычисляемые» столбцы, которые код C # по умолчанию будет читать только как true.

1 Ответ

0 голосов
/ 02 ноября 2018

Вы написали это неправильно? Флаг ReadOnly имеет значение true, и вы надеетесь избежать зацикливания и установите его как false.

Если бы вы предоставили простой выбор, построитель запросов мог бы создавать соответствующие запросы на обновление и удаление, сопоставлять столбцы с параметрами и генерировать доступный для записи набор данных. Это не может сделать это для сложностей, присущих объединенному запросу, потому что потребуется определенное количество логики кодирования, чтобы определить, являются ли столбцы обновляемыми, из какой они таблицы, одинаковые ли столбцы представлены одинаково и т. Д. .. он не предназначен для того, чтобы в основном использовать сложные веб-ресурсы для простых запросов выбора

Просто установите столбцы как доступные для записи и предоставьте запрос на обновление вручную сборщику / адаптеру - пытаясь обмануть вещи, чтобы процесс, который создает таблицу данных из данных, мог догадаться, что эти столбцы не будут доступны только для чтения, быть значительной тратой времени и, вероятно, довольно хрупким ..

Другой вариант, который у вас есть, - не выполнять объединение, вместо этого сделайте две заливки по двум различным запросам из адаптера, у него будет больше шансов на создание обновляемого набора данных и набора команд, если запросы не объединены, union , группы и т. д.

Или используйте конструктор набора данных и создайте новый набор данных, который разработан и строго типизирован для представления того, что вам нужно

Из всех вариантов я бы выбрал последнее, что вы пытаетесь сделать «правильно» - контейнеры / классы данных должны быть разработаны и строго типизированы; использование общего набора данных не намного «лучше», чем хранение всего в объекте [] [] []

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...