6

我希望能够直接从 SQL Server 数据库读取Dynamics NAV 2013 表元数据,而不需要 NAV 开发环境

我可以使用如下查询查看二进制 SQL“图像”BLOB 列(使用 WHERE 子句进行适当过滤):

SELECT 
    o.[Name],
    m.[Object Type],
    m.[Metadata], -- XML Metadata
    m.[User Code], -- C# Metadata
    m.[User AL Code] -- C/AL Metadata
FROM [Navision].[dbo].[Object Metadata] AS m
JOIN [Navision].[dbo].[Object] AS o
ON m.[Object ID] = o.[ID]
AND o.[Company Name] = 'YourCompanyName'
AND o.[Type] = 0 -- 0 is NAV Table Object Type

我可以使用 .Net 代码或带有 SQL 驱动程序的快速脚本将 [元数据]、[用户代码] 和 [用户 AL 代码] 中的二进制数据保存到文件中。我尝试使用 7-zip 解压缩,使用十六进制编辑器查看,以及 Cygwin“文件”命令来检测这些 BLOB 文件类型。

不幸的是,我无法弄清楚如何将二进制数据解码或解压缩为可读或可用的格式。在我可以直接使用这些字段中的数据之前,我必须打开 NAV Dev Environment 并使用对象设计器查看从零开始的查找列表下拉菜单的逗号分隔的 OptionString 属性(列表中的每个项目都存储在后端数据库作为整数 - 第一项为 0,第二项为 1,依此类推)。SQL 查找表中不存在字符串值,但 NAV 确实将它们放在表元数据 blob 中。

这是我完全支持我的 NAV 用户作为 DBA 而不需要 NAV 开发人员为我查找这些数字到名称的 NAV 自定义字段映射的缺失链接。然后,我可以查找这些列表值并根据需要创建匹配的 SQL CASE 语句或自定义查找表。

一旦我有了这篇文章,我应该能够创建高级 SQL 视图、查询、报告和工具,而无需访问 Dynamics NAV 前端用户或开发人员工具。

如果您了解用于这些 NAV 对象元数据 blob 属性的二进制数据格式,请告诉我。任何关于如何转换为可读或可用格式的建议都会有所帮助。

4

3 回答 3

5

我能够从deV.ch-man vs. code、Dynamics NAV & C# .NET 博客的作者那里获得有关这些元数据二进制字段格式的答案。根据 devch 的逆向工程,我们确定 NAV 使用这些字段的前四个字节(32 位)来存储确定自定义 NAV Blob 类型的“幻数”。

对于这些元数据字段,NAV Compressed Blob-Type 幻数是 0x02457d5b(十六进制)。为了使用标准的 .Net DeflateStream 进行解压缩,只需丢弃前四个幻数字节,然后像往常一样使用 DeflateStream 处理流的其余部分。

我能够使用 .Net 成功测试此过程,现在我计划使用 Python 或其他一些非 Microsoft deflate 工具进行测试,以查看 deflate 实现是否符合行业标准。再次感谢 devch 提供了导致此解决方案的文章:Accessing Compressed Blobs from outside NAV (NAV2013) (Revisited)

更新:用 Python zlib 测试,它可以工作!删除自定义 NAV Blob 类型幻数后,将使用符合标准的 Deflate 算法。这是一些示例代码(Python):

# Example Using Python 3.x
import zlib, sys, struct

# NAV custom Blob-Type identifier (first 4 bytes)
magic = struct.unpack('>I',sys.stdin.buffer.read(4))[0]
print('magic number = %#010x' % magic, file=sys.stderr)
# Remaining binary data is standard DEFLATE without header
input = sys.stdin.buffer.read()
output = zlib.decompress(input,-15)
sys.stdout.buffer.write(output)

使用类似下面的东西来测试:

python -u test.py < Input_Meta.blob > Output_Meta.txt

当然 .Net DeflateStream 在删除前四个字节后也可以工作。此示例只是为了表明您不仅限于使用 .Net 语言。

于 2014-01-21T15:55:22.073 回答
3

可以通过 Nav 从该表中提取metadata,我可以看到它存储为纯文本但在二进制字段中。可以使用简单的方法将其保存到文件中MemoryStream(在 Nav 中称为OutSteram)。所以对于表 3,我得到以下 XML:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<MetaTable xmlns="urn:schemas-microsoft-com:dynamics:NAV:MetaObjects" ID="3" CaptionML="ENU=Payment Terms;RUS=Условия платежа" DataPerCompany="1" Name="Payment Terms" LookupFormID="4" DataCaptionFields="1,5">
    <Fields>
        <Field ID="1" Datatype="Code" DataLength="10" Enabled="1" FieldClass="Normal" Name="Code" CaptionML="ENU=Code;RUS=Код" BlankNumbers="DontBlank" BlankZero="0" SignDisplacement="0" Editable="1" NotBlank="1" Numeric="0" DateFormula="0" ClosingDates="0" Title="0" AutoIncrement="0" ValidateTableRelation="1" TestTableRelation="1" ExtendedDatatype="None"/>
        <Field ID="2" Datatype="DateFormula" Enabled="1" FieldClass="Normal" Name="Due Date Calculation" CaptionML="ENU=Due Date Calculation;RUS=Расчет срока оплаты" BlankNumbers="DontBlank" BlankZero="0" SignDisplacement="0" Editable="1" NotBlank="0" Numeric="0" DateFormula="0" ClosingDates="0" Title="0" AutoIncrement="0" ValidateTableRelation="1" TestTableRelation="1" ExtendedDatatype="None"/>
        <Field ID="3" Datatype="DateFormula" Enabled="1" FieldClass="Normal" Name="Discount Date Calculation" CaptionML="ENU=Discount Date Calculation;RUS=Расчет даты скидки" BlankNumbers="DontBlank" BlankZero="0" SignDisplacement="0" Editable="1" NotBlank="0" Numeric="0" DateFormula="0" ClosingDates="0" Title="0" AutoIncrement="0" ValidateTableRelation="1" TestTableRelation="1" ExtendedDatatype="None"/>
        <Field ID="4" Datatype="Decimal" Enabled="1" FieldClass="Normal" Name="Discount %" CaptionML="ENU=Discount %;RUS=Скидка (%)" BlankNumbers="DontBlank" BlankZero="0" SignDisplacement="0" Editable="1" MinValue="0" MaxValue="100" NotBlank="0" Numeric="0" DateFormula="0" ClosingDates="0" Title="0" AutoIncrement="0" ValidateTableRelation="1" TestTableRelation="1" ExtendedDatatype="None"/>
        <Field ID="5" Datatype="Text" DataLength="50" Enabled="1" FieldClass="Normal" Name="Description" CaptionML="ENU=Description;RUS=Описание" BlankNumbers="DontBlank" BlankZero="0" SignDisplacement="0" Editable="1" NotBlank="0" Numeric="0" DateFormula="0" ClosingDates="0" Title="0" AutoIncrement="0" ValidateTableRelation="1" TestTableRelation="1" ExtendedDatatype="None"/>
        <Field ID="6" Datatype="Boolean" Enabled="1" FieldClass="Normal" Name="Calc. Pmt. Disc. on Cr. Memos" CaptionML="ENU=Calc. Pmt. Disc. on Cr. Memos;RUS=Расчет скидки оплаты по кредит-нотам" BlankNumbers="DontBlank" BlankZero="0" SignDisplacement="0" Editable="1" NotBlank="0" Numeric="0" DateFormula="0" ClosingDates="0" Title="0" AutoIncrement="0" ValidateTableRelation="1" TestTableRelation="1" ExtendedDatatype="None"/>
    </Fields>
    <Keys>
        <Key Enabled="1" Key="Field1" MaintainSQLIndex="1" MaintainSIFTIndex="1" Clustered="1"/>
    </Keys>
    <FieldGroups>
        <FieldGroup GroupID="1" GroupName="DropDown" GroupFields="Field1,Field5,Field2"/>
    </FieldGroups>
</MetaTable>

假设这是你想要的。

将其写入 Nav 文件的代码如下所示:

ObjectMetadata:Record(Object Metadata)
Code:BigText
File:File       
CodeStream:InStream     
FileStream:OutStream        

ObjectMetadata.INIT;

IF ObjectMetadata.GET(1,3) THEN
 BEGIN
  ObjectMetadata.CALCFIELDS(Metadata);
  File.CREATE('C:\temp\Code.txt');
  File.CREATEOUTSTREAM(FileStream);

  clear(codestream);
  ObjectMetadata."Metadata".CREATEINSTREAM(CodeStream);
  Code.READ(CodeStream);
  Code.WRITE(FileStream);

  file.close();
 END;

现在您有选择:尝试在 SQL/.Net 中做同样的事情(我不喜欢它),或者您可以要求您的导航开发人员进行某种批处理作业,该批处理作业将定期(或按需)处理所有表' matadata 并将其保存到外部表/文件/您可以从 SQL 访问的任何内容。

于 2014-01-20T10:08:01.450 回答
1

为什么不使用 Web 服务并获得所需的数据而无需做任何花哨的事情呢?

然后,用户可以使用 PowerPivot for Excel 并创建自己的报告。

您还可以使用用于 NAV 的 Excel 加载项,直接从 NAV 将数据导出到 Excel,然后从 Excel 中刷新。

于 2015-02-10T16:13:45.483 回答