FormDataSource中Outer Join属性的一个Bug
郁闷了一天,终于解决了一个问题,再次强烈鄙视Dynamics Ax的文档,很多很奇怪的用法一点文档介绍都没有!!
问题描述:
为了给InventSum表中每个ItemId和InventDimId的组合创建一个属性,又不改变这个表的结构,新建了一张名为InventSumProperty的表,字段描述如下:
ItemId:料品Id
InventDimId:库房维组Id
Property:新增加的属性
增加一个跟表InventSum的连接,连接字段为ItemId和InventDimId
为了展示这些属性,新建了一个Form,由于需要显示某些物料和库存纬度的值,于是InventSum需要跟InventDim表内联,然后再跟InventSumProperty外联。
这样这个Form就有三个数据源
InventSum JoinSource:空 LinkType:Delayed
InventDim JoinSource:InventSum LinkType:InnerJoin
InventSumProperty JoinSource:InventSum LinkType:OuterJoin
将某些想展现的东东放到Grid里,本来以为万事大吉了,谁想到让俺着实郁闷了一把,打开窗体时迎接俺的是如下的错误:
无法选择 InventSumExternal (InventSumExternal) 中的记录。该联接在 WHERE 子句中的联接表之间不包含任何链接。
这个提示还真是莫名奇妙,不包含任何连接??明明在表InventSumExternal上加了连接啊......怪哉!
排查过程
以前做过蛮多三个表之间的内联,于是试着InventSumproperty的LinkType改成InnerJoin,果然这样就不报错了!但是这还是不能满足要求,因为如果改成InnerJoin,很多InventSum表中存在但在InventSumProperty中没有对应属性的值将不会显示,这不符合要求。
看了一下是在执行InventSum_ds的ExcuteQuery方法时出错的,用SQL跟踪没有跟踪到任何语句,看来是在语句分析阶段就出错了,没有执行SQL语句。
重载InventSum_ds的ExcuteQuery方法,在Super之前写入一下代码:
分别改装成真正的SQL版本和X++版本如下:
SQL版本:
X++版本:
如果能想办法让FormDataSource对应的Query生成的X++查询代码也是OUTERJOIN在前,INNERJOIN在后问题应该就解决了?试着将InventSumExternal_ds挪到InventDim_ds的前面,没有任何作用。。。。。。
这个查询应该是在调用各个数据源的Init方法时构造出来的,前面测试过Init方法的执行顺序,当时还真是让人费解,貌似执行顺序不定,可能先执行这个,也可能后执行那个,并且与DataSource在Form中显示的次序没有关系。突然记起前面测试的时候先后创建的两个Form,用的是同样的两个数据源,结果两个数据源的Init方法调用的顺序正好相反,难道跟刚刚创建DataSource时的顺序有关???
重新创建了一个Form,仍然使用上述三个DataSource,只不过在创建的时候按如下顺序
InventSum,InventSumExternal,InventDim
连接数据源和连接方式仍然按照前面的设定。
NND,居然OK了!!
彻底搞不懂了......
结论:
X++的解释器有bug,如果有两个数据源分别通过InnerJoin和OuterJoin关联到同一个数据源上,那么一定要记得在创建数据源的时候,连接关系为OuterJoin的数据源一定要先于InnerJoin的数据源创建。
那位又问了?要是两个数据源都通过OuterJoin连接到同一个数据源该怎么办?
您老就别难为AX了吧,恐怕这个它压根就没考虑,要不您试试看?
问题描述:
为了给InventSum表中每个ItemId和InventDimId的组合创建一个属性,又不改变这个表的结构,新建了一张名为InventSumProperty的表,字段描述如下:
ItemId:料品Id
InventDimId:库房维组Id
Property:新增加的属性
增加一个跟表InventSum的连接,连接字段为ItemId和InventDimId
为了展示这些属性,新建了一个Form,由于需要显示某些物料和库存纬度的值,于是InventSum需要跟InventDim表内联,然后再跟InventSumProperty外联。
这样这个Form就有三个数据源
InventSum JoinSource:空 LinkType:Delayed
InventDim JoinSource:InventSum LinkType:InnerJoin
InventSumProperty JoinSource:InventSum LinkType:OuterJoin
将某些想展现的东东放到Grid里,本来以为万事大吉了,谁想到让俺着实郁闷了一把,打开窗体时迎接俺的是如下的错误:
无法选择 InventSumExternal (InventSumExternal) 中的记录。该联接在 WHERE 子句中的联接表之间不包含任何链接。
这个提示还真是莫名奇妙,不包含任何连接??明明在表InventSumExternal上加了连接啊......怪哉!
排查过程
以前做过蛮多三个表之间的内联,于是试着InventSumproperty的LinkType改成InnerJoin,果然这样就不报错了!但是这还是不能满足要求,因为如果改成InnerJoin,很多InventSum表中存在但在InventSumProperty中没有对应属性的值将不会显示,这不符合要求。
看了一下是在执行InventSum_ds的ExcuteQuery方法时出错的,用SQL跟踪没有跟踪到任何语句,看来是在语句分析阶段就出错了,没有执行SQL语句。
重载InventSum_ds的ExcuteQuery方法,在Super之前写入一下代码:
info(InventSum_DS.query().dataSourceNo(1).toString());
最终得到如下SQL语句SELECT * FROM InventSum
JOIN * FROM InventDim
WHERE InventSum.InventDimId = InventDim.inventDimId
OUTER JOIN * FROM InventSumExternal
WHERE InventSum.ItemId = InventSumExternal.ItemId AND InventSum.InventDimId = InventSumExternal.InventDimId
这个语句应该是提交给SQL Server分析的语句,当然这个语句只是个半成品,在SQL Server中不能执行,在X++中也有语法错误。JOIN * FROM InventDim
WHERE InventSum.InventDimId = InventDim.inventDimId
OUTER JOIN * FROM InventSumExternal
WHERE InventSum.ItemId = InventSumExternal.ItemId AND InventSum.InventDimId = InventSumExternal.InventDimId
分别改装成真正的SQL版本和X++版本如下:
SQL版本:
SELECT * FROM InventSum
INNER JOIN InventDim ON InventSum.InventDimId = InventDim.inventDimId
LEFT JOIN InventSumExternal ON InventSum.InventDimId = InventSumExternal.InventDimId
上面这个语句在SQL Server运行没有任何问题INNER JOIN InventDim ON InventSum.InventDimId = InventDim.inventDimId
LEFT JOIN InventSumExternal ON InventSum.InventDimId = InventSumExternal.InventDimId
X++版本:
static void sqlTest(Args _args)
{
InventSum inventSum;
InventDim inventDim;
InventSumExternal inventSumExternal;
;
SELECT * FROM inventSum
JOIN * FROM inventDim
WHERE InventSum.InventDimId == InventDim.inventDimId
OUTER JOIN * FROM inventSumExternal
WHERE InventSum.ItemId == InventSumExternal.ItemId &&
InventSum.InventDimId == InventSumExternal.InventDimId;
}
运行上面的语句,报出了与采用Form时一样的错!!看来问题出在这上面了,X++编译器在编译这个语句的时候有Bug,不能生成正确的SQL语句!郁闷死了......在这里卡壳了好半天,试来试去,突然想到把OUTER JOIN的顺序移到JOIN前面试试看。{
InventSum inventSum;
InventDim inventDim;
InventSumExternal inventSumExternal;
;
SELECT * FROM inventSum
JOIN * FROM inventDim
WHERE InventSum.InventDimId == InventDim.inventDimId
OUTER JOIN * FROM inventSumExternal
WHERE InventSum.ItemId == InventSumExternal.ItemId &&
InventSum.InventDimId == InventSumExternal.InventDimId;
}
static void sqlTest(Args _args)
{
InventSum inventSum;
InventDim inventDim;
InventSumExternal inventSumExternal;
;
SELECT * FROM inventSum
OUTER JOIN * FROM inventSumExternal
WHERE InventSum.ItemId == InventSumExternal.ItemId &&
InventSum.InventDimId == InventSumExternal.InventDimId
JOIN * FROM inventDim
WHERE InventSum.InventDimId == InventDim.inventDimId;
}
ft!没想到这样就OK了!真是让人费解啊!{
InventSum inventSum;
InventDim inventDim;
InventSumExternal inventSumExternal;
;
SELECT * FROM inventSum
OUTER JOIN * FROM inventSumExternal
WHERE InventSum.ItemId == InventSumExternal.ItemId &&
InventSum.InventDimId == InventSumExternal.InventDimId
JOIN * FROM inventDim
WHERE InventSum.InventDimId == InventDim.inventDimId;
}
如果能想办法让FormDataSource对应的Query生成的X++查询代码也是OUTERJOIN在前,INNERJOIN在后问题应该就解决了?试着将InventSumExternal_ds挪到InventDim_ds的前面,没有任何作用。。。。。。
这个查询应该是在调用各个数据源的Init方法时构造出来的,前面测试过Init方法的执行顺序,当时还真是让人费解,貌似执行顺序不定,可能先执行这个,也可能后执行那个,并且与DataSource在Form中显示的次序没有关系。突然记起前面测试的时候先后创建的两个Form,用的是同样的两个数据源,结果两个数据源的Init方法调用的顺序正好相反,难道跟刚刚创建DataSource时的顺序有关???
重新创建了一个Form,仍然使用上述三个DataSource,只不过在创建的时候按如下顺序
InventSum,InventSumExternal,InventDim
连接数据源和连接方式仍然按照前面的设定。
NND,居然OK了!!
彻底搞不懂了......
结论:
X++的解释器有bug,如果有两个数据源分别通过InnerJoin和OuterJoin关联到同一个数据源上,那么一定要记得在创建数据源的时候,连接关系为OuterJoin的数据源一定要先于InnerJoin的数据源创建。
那位又问了?要是两个数据源都通过OuterJoin连接到同一个数据源该怎么办?
您老就别难为AX了吧,恐怕这个它压根就没考虑,要不您试试看?