我正在尝试获取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;
});
}
我一直在研究这个问题,发现没有union
的{{1}}可以很好地填充并将列上的DataTable
属性设置为false。所以我知道这与工会有关,但我不确定为什么。
我知道之前已经以类似的方式问过这个问题,但是我不想在ReadOnly
列中循环并手动将DataTable
属性设置为true,我想修复从根本上解决问题。
谢谢!
更新:我相信是因为这些列被归类为“计算”列,C#代码会将这些列默认只读为true。
答案 0 :(得分:1)
您写错了吗? ReadOnly标志为true,您希望避免循环并将其设置为false。
如果您提供一个简单的选择,则查询构建器将能够创建匹配的更新和删除查询,将列映射到参数并生成可写数据集。对于联合查询固有的复杂性,它无法做到这一点,因为要花费大量的编码逻辑才能确定这些列是否可更新,它们来自哪个表,相同的列是否以相同的方式呈现等等。 ..并非设计复杂的网络主要是为了使用简单的选择查询
只需将列设置为可写,并向构建器/适配器手动提供更新查询-尝试捏造事物,以便从数据创建数据表的过程可以猜测不会使这些列变为只读相当浪费时间,而且可能很脆弱。
您还有另一个选择是不执行联合,而是对适配器的两个不同查询执行两次填充,如果查询中没有联接,联合,则将有更好的机会生成可更新的数据集和命令集合,组等
或者使用数据集设计器并创建一个新的数据集,该数据集经过专门设计并经过严格键入以表示您的需求
在所有选项中,我会选择您要“正确”执行的最后一个选项-数据容器/类应设计并进行强类型化;使用通用数据集比将所有内容存储在对象中[“ [] [] []