【问题标题】:DataTable columns are set as ReadOnly when using a union使用联合时,DataTable 列设置为只读
【发布时间】:2018-11-01 18:18:16
【问题描述】:

我正在尝试获取 DataTable 并稍后在我的程序中更新它,但是当我尝试修改我的一个列 (IsUsed) 时收到 System.Exception。错误显示“已读取列 IsUsed只要'。这是真的,DataTable 中的列将ReadOnly 属性设置为 true。

这是生成我的 SQL 的 C# 代码:

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;
                                });
    }

我一直在玩这个,我发现如果没有unionDataTable 可以很好地填充并将列上的ReadOnly 属性设置为 false。所以我知道这与工会有关,但我不确定为什么。

我知道以前曾以类似的方式提出过这个问题,但我不想循环 DataTable 列并手动将 ReadOnly 属性设置为 true,我想在来源。

谢谢!

更新:我相信这是因为这些列被归类为“计算”列,C# 代码将默认只读为 true。

【问题讨论】:

    标签: c# sql datatable union


    【解决方案1】:

    你写错了吗? ReadOnly 标志为真,您希望避免循环并将其设置为假。

    如果您提供简单的选择,查询构建器将能够创建匹配的更新和删除查询、将列映射到参数并生成可写数据集。对于联合查询中固有的复杂性,它不能这样做,因为需要大量的编码逻辑来确定列是否可更新,它们来自哪个表,相同的列是否以相同的方式呈现等.. 它的设计初衷不是为了消费简单的选择查询而成为复杂的网络

    只需将列设置为可写并手动向构建器/适配器提供更新查询 - 试图捏造一些东西,以便从数据创建数据表的过程可以猜测不使这些列只读相当浪费时间,而且可能相当脆弱..

    您的另一个选择是不进行联合,而是对来自适配器的两个不同查询进行两次填充,如果查询没有连接,则它将更有可能生成可更新的数据集和命令集合,联合,组等

    或者使用数据集设计器并创建一个新的数据集,该数据集经过设计和强类型化以表示您需要的内容

    在所有选项中,我会选择您尝试“正确”执行此操作的最后一个 - 数据容器/类应设计为强类型;使用通用数据集并不比将所有内容存储在对象中“更好”[][][]

    【讨论】:

      猜你喜欢
      • 2015-07-03
      • 2012-06-23
      • 2016-10-27
      • 2015-03-13
      • 2017-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多