【问题标题】:Read Dynamics NAV Table Metadata with SQL使用 SQL 读取 Dynamics NAV 表元数据
【发布时间】:2014-01-19 22:55:12
【问题描述】:

我希望能够在没有requiring the NAV Development Environment 的情况下直接从 SQL Server 数据库中读取Dynamics NAV 2013 Table Metadata

我可以使用如下查询查看二进制 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 文件类型。

不幸的是,我不知道如何将二进制数据解码或解压缩为可读或可用的格式。在我可以直接使用这些字段中的数据之前,我必须 open NAV Dev Environment and use the Object Designer to view the comma-separated OptionString properties 用于从零开始的查找列表下拉菜单(列表中的每个项目都以整数形式存储在后端数据库中 - 第一项为 0,1第二个等)。 SQL 查找表中不存在字符串值,但 NAV 确实将它们放在表元数据 blob 中。

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

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

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

【问题讨论】:

    标签: tsql blob zlib dynamics-nav deflatestream


    【解决方案1】:

    我能够从deV.ch - man vs. code, Dynamics NAV & C# .NET blog 的作者那里得到有关这些元数据二进制字段格式的答案。根据 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 语言。

    【讨论】:

    • 太棒了!微软再次出人意料。为什么要添加 4 个愚蠢的字节?
    • @MakSim 我认为这是一个类型前缀,因此如果他们愿意,他们可以以不同的格式存储内容..
    • @VincentVancalbergh 虽然导航中没有这样的功能
    • @MakSim 他们可能会加一个!
    • 不适用于 NAV 2009,但仍适用于 NAV 2018
    【解决方案2】:

    可以通过 Nav 从此表中提取 metadata,我可以看到它以纯文本形式存储,但在二进制字段中。可以使用简单的MemoryStream 将其保存到文件中(在导航中称为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 中做同样的事情(我不喜欢它),或者您可以要求您的导航开发人员进行某种批处理作业,该批处理作业将定期(或按需)处理所有表的元数据并将其保存到外部表/文件/您可以从 SQL 访问的任何内容。

    【讨论】:

    • 感谢 Mak 的回答,虽然我更喜欢直接从 SQL/.Net 访问 NAV 元数据的能力,但拥有一个我的 NAV 开发人员可以用来提供此元数据的代码示例会很有帮助我。
    【解决方案3】:

    为什么不用网络服务来获取你需要的数据而不用做任何花哨的事情呢?

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

    您也可以使用用于 NAV 的 Excel 插件,直接从 NAV 将数据导出到 Excel,然后在 Excel 中刷新。

    【讨论】:

    • 创建一个网络服务听起来很花哨。是否有内置于 NAV 中的 Web 服务可以轻松访问数据?请提供一个简单示例,说明如何利用此 Web 服务功能让 NAV 用户轻松访问数据。您是否有用于 NAV 的 Excel 加载项的链接或示例?我没听说过 - 它是 Microsoft 提供的组件吗?
    • 网络服务内置于 NAV。如果您在角色中心的搜索栏中键入Web Services,则可以发布页面、代码单元或查询并通过 SOAP 或 ODATA 使其可用。 saurav-nav.blogspot.co.uk/2013/11/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-14
    • 1970-01-01
    相关资源
    最近更新 更多