Skip to Content
Product Information
Author's profile photo Xiao-fei Song

An introduction to OData CSDL Modeler for Visual Studio Code

In this blog post, we’ll introduce a new lightweight tool OData CSDL modeler for OData developers to view OData metadata CSDL document in a graphical manner in Visual Studio Code so that they can understand the structure of OData metadata more easily.

Usage of OData CSDL modeler for VSCODE

You can very easily find OData CSDL Modeler in VSCODE Marketplace at https://marketplace.visualstudio.com/items?itemName=SAPSE.vsc-extension-odata-csdl-modeler, and install the extension to your VSCODE development environment.

In order to use the CSDL modeler to view your OData metadata CSDL document, you need to download and copy the CSDL document locally:

Right click the edmx file on the VSCODE left pane, click “Open With…” context menu:

In the VSCODE command palette dialog, select “Open with OData CSDL Modeler”:

Now you will be able to see the OData metadata document is loaded successfully by the OData CSDL Modeler:

You can also see the entity sets on the property sheet as well:

Conclusion

In the blog post, we introduced a new tool “OData CSDL Modeler” in VSCODE Marketplace that enables OData developers to view complex OData metadata CSDL documents in a graphical manner so that they can understand OData CSDL structure more easily.

Assigned Tags

      7 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo DJ Adams
      DJ Adams

      Thanks, this great, and very timely! We may have to explore this extension in this coming Friday's Hands-on SAP Dev live stream 🙂 Thanks also to Ralf Handl for alerting me to this.

      Author's profile photo Xiao-fei Song
      Xiao-fei Song
      Blog Post Author

      Great DJ Adams! Any feedback would be appreciated after you evaluate the tool.

      Author's profile photo Jayanta Choudhuri
      Jayanta Choudhuri

      Hi Xiao-Fei

      OData CSDL Modeler seems not to work for me

      I downloaded XML from the URL
      http://vhcala4hci:50000//sap/opu/odata/sap/ZDEMO_DDL_SPFLI_CDS/$metadata?sap-client=001&sap-language=EN

      I downloaded and kept it all in text file myCSDL.metadata.xml
      Open With shows "Open with CSDL Modeler"

      myCSDL.metadata.xml

      <edmx:Edmx xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:sap="http://www.sap.com/Protocols/SAPData" Version="1.0">
      <edmx:Reference xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Uri="http://vhcala4hci:50000/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_COMMON',Version='0001',SAP__Origin='LOCAL')/$value">
      <edmx:Include Namespace="com.sap.vocabularies.Common.v1" Alias="Common"/>
      </edmx:Reference>
      <edmx:Reference xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Uri="http://vhcala4hci:50000/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_CAPABILITIES',Version='0001',SAP__Origin='LOCAL')/$value">
      <edmx:Include Namespace="Org.OData.Capabilities.V1" Alias="Capabilities"/>
      </edmx:Reference>
      <edmx:Reference xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Uri="http://vhcala4hci:50000/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_COMMUNICATION',Version='0001',SAP__Origin='LOCAL')/$value">
      <edmx:Include Namespace="com.sap.vocabularies.Communication.v1" Alias="Communication"/>
      </edmx:Reference>
      <edmx:Reference xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Uri="http://vhcala4hci:50000/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_AGGREGATION',Version='0001',SAP__Origin='LOCAL')/$value">
      <edmx:Include Namespace="Org.OData.Aggregation.V1" Alias="Aggregation"/>
      </edmx:Reference>
      <edmx:Reference xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Uri="http://vhcala4hci:50000/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Vocabularies(TechnicalName='%2FIWBEP%2FVOC_PERSONALDATA',Version='0001',SAP__Origin='LOCAL')/$value">
      <edmx:Include Namespace="com.sap.vocabularies.PersonalData.v1" Alias="PersonalData"/>
      </edmx:Reference>
      <edmx:DataServices m:DataServiceVersion="2.0">
      <Schema xmlns="http://schemas.microsoft.com/ado/2008/09/edm" Namespace="ZDEMO_DDL_SPFLI_CDS" xml:lang="en" sap:schema-version="1">
      <EntityType Name="ZDEMO_DDL_SCURXType" sap:label="Currency Table for Value Help" sap:content-version="1">
      <Key>
      <PropertyRef Name="currkey"/>
      </Key>
      <Property Name="currkey" Type="Edm.String" Nullable="false" MaxLength="5" sap:label="Paymnt currency" sap:quickinfo="Payment currency" sap:semantics="currency-code"/>
      <Property Name="currdec" Type="Edm.Byte" sap:label="Decimals" sap:quickinfo="Number of decimal places"/>
      </EntityType>
      <EntityType Name="ZDEMO_DDL_SFLIGHTType" sap:label="List reporting for Flight Details" sap:content-version="1">
      <Key>
      <PropertyRef Name="AirlineCode"/>
      <PropertyRef Name="FlightConnectionNo"/>
      <PropertyRef Name="FlightDate"/>
      </Key>
      <Property Name="AirlineCode" Type="Edm.String" Nullable="false" MaxLength="3" sap:display-format="UpperCase" sap:text="CarrierName" sap:label="Airline Code#" sap:quickinfo="Airline Code part of key"/>
      <Property Name="FlightConnectionNo" Type="Edm.String" Nullable="false" MaxLength="4" sap:display-format="NonNegative" sap:label="Connection Number" sap:quickinfo="Flight Connection Id"/>
      <Property Name="FlightDate" Type="Edm.DateTime" Nullable="false" Precision="0" sap:display-format="Date" sap:label="Flight Date" sap:quickinfo="Date of Flight"/>
      <Property Name="Airfare" Type="Edm.Decimal" Precision="16" Scale="3" sap:unit="LocalCurrency" sap:label="Airfare"/>
      <Property Name="LocalCurrency" Type="Edm.String" MaxLength="5" sap:label="Airline Currency" sap:quickinfo="Local currency of airline" sap:value-list="standard" sap:semantics="currency-code"/>
      <Property Name="AircraftType" Type="Edm.String" MaxLength="10" sap:display-format="UpperCase" sap:label="Plane Type" sap:quickinfo="Aircraft Type"/>
      <Property Name="total_max_seat" Type="Edm.Int32" sap:label="Total Seats" sap:creatable="false" sap:updatable="false"/>
      <Property Name="total_avail_seat" Type="Edm.Int32" sap:label="Available Seats" sap:creatable="false" sap:updatable="false"/>
      <Property Name="SeatsMaxEco" Type="Edm.Int32" sap:label="Max. capacity econ." sap:quickinfo="Maximum capacity in economy class"/>
      <Property Name="SeatsOccEco" Type="Edm.Int32" sap:label="Occupied econ." sap:quickinfo="Occupied seats in economy class"/>
      <Property Name="TotalCurrBook" Type="Edm.Decimal" Precision="18" Scale="3" sap:unit="LocalCurrency" sap:label="Booking total" sap:quickinfo="Total of current bookings"/>
      <Property Name="SeatsMaxBus" Type="Edm.Int32" sap:label="Max. capacity bus." sap:quickinfo="Maximum capacity in business class"/>
      <Property Name="SeatsOccBus" Type="Edm.Int32" sap:label="Occupied bus." sap:quickinfo="Occupied seats in business class"/>
      <Property Name="SeatsMaxFirst" Type="Edm.Int32" sap:label="Max. capacity 1st" sap:quickinfo="Maximum capacity in first class"/>
      <Property Name="SeatsOccFirst" Type="Edm.Int32" sap:label="Occupied 1st" sap:quickinfo="Occupied seats in first class"/>
      <Property Name="CarrierName" Type="Edm.String" MaxLength="20" sap:label="Airline" sap:quickinfo="Airline name" sap:creatable="false" sap:updatable="false"/>
      <Property Name="Criticality" Type="Edm.Byte" sap:creatable="false" sap:updatable="false"/>
      <NavigationProperty Name="to_currencyValueHelp" Relationship="ZDEMO_DDL_SPFLI_CDS.assoc_3397C1522555AF6EC96BFCE26F8C8EFC" FromRole="FromRole_assoc_3397C1522555AF6EC96BFCE26F8C8EFC" ToRole="ToRole_assoc_3397C1522555AF6EC96BFCE26F8C8EFC"/>
      </EntityType>
      <EntityType Name="ZDEMO_DDL_SPFLIType" sap:label="Consumption CDS for SPFLI" sap:content-version="1">
      <Key>
      <PropertyRef Name="AirlineCode"/>
      <PropertyRef Name="FlightConnectionNo"/>
      </Key>
      <Property Name="Copy_ac" Type="Edm.Boolean" sap:label="Dyn. Action Control" sap:creatable="false" sap:updatable="false" sap:sortable="false" sap:filterable="false"/>
      <Property Name="AirlineCode" Type="Edm.String" Nullable="false" MaxLength="3" sap:display-format="UpperCase" sap:text="CarrierName" sap:label="Airline Code#" sap:quickinfo="Airline Code part of key" sap:creatable="false" sap:updatable="false"/>
      <Property Name="FlightConnectionNo" Type="Edm.String" Nullable="false" MaxLength="4" sap:display-format="NonNegative" sap:label="Connection Number" sap:quickinfo="Flight Connection Id" sap:creatable="false" sap:updatable="false"/>
      <Property Name="CountryFrom" Type="Edm.String" MaxLength="3" sap:display-format="UpperCase" sap:label="Country From" sap:quickinfo="Airline Country From"/>
      <Property Name="CityFrom" Type="Edm.String" MaxLength="20" sap:display-format="UpperCase" sap:label="Depart. city" sap:quickinfo="Departure city"/>
      <Property Name="AirportFrom" Type="Edm.String" MaxLength="3" sap:display-format="UpperCase" sap:label="Departure airport"/>
      <Property Name="CountryTo" Type="Edm.String" MaxLength="3" sap:display-format="UpperCase" sap:label="Country To" sap:quickinfo="Airline Country To"/>
      <Property Name="CityTo" Type="Edm.String" MaxLength="20" sap:display-format="UpperCase" sap:label="Arrival city"/>
      <Property Name="AirportTo" Type="Edm.String" MaxLength="3" sap:display-format="UpperCase" sap:label="Destination airport"/>
      <Property Name="DepartureTime" Type="Edm.Time" Precision="0" sap:label="Departure time"/>
      <Property Name="ArrivalTime" Type="Edm.Time" Precision="0" sap:label="Arrival Time" sap:quickinfo="Arrival time"/>
      <Property Name="Distance" Type="Edm.Decimal" Precision="9" Scale="4" sap:label="Distance"/>
      <Property Name="DistanceId" Type="Edm.String" MaxLength="3" sap:label="Distance in" sap:quickinfo="Mass unit of distance (kms, miles)" sap:semantics="unit-of-measure"/>
      <Property Name="FlightType" Type="Edm.String" MaxLength="1" sap:display-format="UpperCase" sap:label="Charter flt" sap:quickinfo="Flight type"/>
      <Property Name="Period" Type="Edm.Byte" sap:label="n day(s) later" sap:quickinfo="Arrival n day(s) later"/>
      <Property Name="Criticality" Type="Edm.Byte" sap:creatable="false" sap:updatable="false"/>
      <Property Name="CarrierName" Type="Edm.String" MaxLength="20" sap:label="Airline" sap:quickinfo="Airline name" sap:creatable="false" sap:updatable="false"/>
      <NavigationProperty Name="to_flight" Relationship="ZDEMO_DDL_SPFLI_CDS.assoc_F4B6D14BB80A396A9AFD7E20D89D91DA" FromRole="FromRole_assoc_F4B6D14BB80A396A9AFD7E20D89D91DA" ToRole="ToRole_assoc_F4B6D14BB80A396A9AFD7E20D89D91DA"/>
      </EntityType>
      <ComplexType Name="DummyFunctionImportResult">
      <Property Name="IsInvalid" Type="Edm.Boolean" sap:label="TRUE"/>
      </ComplexType>
      <Association Name="assoc_3397C1522555AF6EC96BFCE26F8C8EFC" sap:content-version="1">
      <End Type="ZDEMO_DDL_SPFLI_CDS.ZDEMO_DDL_SFLIGHTType" Multiplicity="1" Role="FromRole_assoc_3397C1522555AF6EC96BFCE26F8C8EFC"/>
      <End Type="ZDEMO_DDL_SPFLI_CDS.ZDEMO_DDL_SCURXType" Multiplicity="0..1" Role="ToRole_assoc_3397C1522555AF6EC96BFCE26F8C8EFC"/>
      </Association>
      <Association Name="assoc_F4B6D14BB80A396A9AFD7E20D89D91DA" sap:content-version="1">
      <End Type="ZDEMO_DDL_SPFLI_CDS.ZDEMO_DDL_SPFLIType" Multiplicity="1" Role="FromRole_assoc_F4B6D14BB80A396A9AFD7E20D89D91DA"/>
      <End Type="ZDEMO_DDL_SPFLI_CDS.ZDEMO_DDL_SFLIGHTType" Multiplicity="*" Role="ToRole_assoc_F4B6D14BB80A396A9AFD7E20D89D91DA"/>
      </Association>
      <EntityContainer Name="ZDEMO_DDL_SPFLI_CDS_Entities" m:IsDefaultEntityContainer="true" sap:message-scope-supported="true" sap:supported-formats="atom json xlsx">
      <EntitySet Name="ZDEMO_DDL_SCURX" EntityType="ZDEMO_DDL_SPFLI_CDS.ZDEMO_DDL_SCURXType" sap:creatable="false" sap:updatable="false" sap:deletable="false" sap:searchable="true" sap:content-version="1"/>
      <EntitySet Name="ZDEMO_DDL_SFLIGHT" EntityType="ZDEMO_DDL_SPFLI_CDS.ZDEMO_DDL_SFLIGHTType" sap:searchable="true" sap:content-version="1"/>
      <EntitySet Name="ZDEMO_DDL_SPFLI" EntityType="ZDEMO_DDL_SPFLI_CDS.ZDEMO_DDL_SPFLIType" sap:searchable="true" sap:content-version="1"/>
      <AssociationSet Name="assoc_F4B6D14BB80A396A9AFD7E20D89D91DA" Association="ZDEMO_DDL_SPFLI_CDS.assoc_F4B6D14BB80A396A9AFD7E20D89D91DA" sap:creatable="false" sap:updatable="false" sap:deletable="false" sap:content-version="1">
      <End EntitySet="ZDEMO_DDL_SPFLI" Role="FromRole_assoc_F4B6D14BB80A396A9AFD7E20D89D91DA"/>
      <End EntitySet="ZDEMO_DDL_SFLIGHT" Role="ToRole_assoc_F4B6D14BB80A396A9AFD7E20D89D91DA"/>
      </AssociationSet>
      <AssociationSet Name="assoc_3397C1522555AF6EC96BFCE26F8C8EFC" Association="ZDEMO_DDL_SPFLI_CDS.assoc_3397C1522555AF6EC96BFCE26F8C8EFC" sap:creatable="false" sap:updatable="false" sap:deletable="false" sap:content-version="1">
      <End EntitySet="ZDEMO_DDL_SFLIGHT" Role="FromRole_assoc_3397C1522555AF6EC96BFCE26F8C8EFC"/>
      <End EntitySet="ZDEMO_DDL_SCURX" Role="ToRole_assoc_3397C1522555AF6EC96BFCE26F8C8EFC"/>
      </AssociationSet>
      <FunctionImport Name="ZDEMO_DDL_SPFLICopy" ReturnType="ZDEMO_DDL_SPFLI_CDS.DummyFunctionImportResult" m:HttpMethod="POST" sap:action-for="ZDEMO_DDL_SPFLI_CDS.ZDEMO_DDL_SPFLIType" sap:applicable-path="Copy_ac">
      <Parameter Name="AirlineCode" Type="Edm.String" Mode="In" MaxLength="3"/>
      <Parameter Name="FlightConnectionNo" Type="Edm.String" Mode="In" MaxLength="4"/>
      </FunctionImport>
      </EntityContainer>
      <Annotations xmlns="http://docs.oasis-open.org/odata/ns/edm" Target="ZDEMO_DDL_SPFLI_CDS.ZDEMO_DDL_SFLIGHTType/LocalCurrency">
      <Annotation Term="Common.ValueList">
      <Record>
      <PropertyValue Property="Label" String="Currency Table for Value Help"/>
      <PropertyValue Property="CollectionPath" String="ZDEMO_DDL_SCURX"/>
      <PropertyValue Property="SearchSupported" Bool="true"/>
      <PropertyValue Property="Parameters">
      <Collection>
      <Record Type="Common.ValueListParameterInOut">
      <PropertyValue Property="LocalDataProperty" PropertyPath="LocalCurrency"/>
      <PropertyValue Property="ValueListProperty" String="currkey"/>
      </Record>
      <Record Type="Common.ValueListParameterDisplayOnly">
      <PropertyValue Property="ValueListProperty" String="currdec"/>
      </Record>
      </Collection>
      </PropertyValue>
      </Record>
      </Annotation>
      </Annotations>
      <Annotations xmlns="http://docs.oasis-open.org/odata/ns/edm" Target="ZDEMO_DDL_SPFLI_CDS.ZDEMO_DDL_SPFLI_CDS_Entities">
      <Annotation Term="Aggregation.ApplySupported">
      <Record>
      <PropertyValue Property="Transformations">
      <Collection>
      <String>aggregate</String>
      <String>groupby</String>
      <String>filter</String>
      </Collection>
      </PropertyValue>
      <PropertyValue Property="Rollup" EnumMember="None"/>
      </Record>
      </Annotation>
      </Annotations>
      <Annotations xmlns="http://docs.oasis-open.org/odata/ns/edm" Target="ZDEMO_DDL_SPFLI_CDS.ZDEMO_DDL_SFLIGHTType/AirlineCode">
      <Annotation Term="Common.FieldControl" EnumMember="Common.FieldControlType/Mandatory"/>
      </Annotations>
      <Annotations xmlns="http://docs.oasis-open.org/odata/ns/edm" Target="ZDEMO_DDL_SPFLI_CDS.ZDEMO_DDL_SFLIGHTType/FlightConnectionNo">
      <Annotation Term="Common.FieldControl" EnumMember="Common.FieldControlType/Mandatory"/>
      </Annotations>
      <Annotations xmlns="http://docs.oasis-open.org/odata/ns/edm" Target="ZDEMO_DDL_SPFLI_CDS.ZDEMO_DDL_SFLIGHTType/FlightDate">
      <Annotation Term="Common.FieldControl" EnumMember="Common.FieldControlType/Mandatory"/>
      </Annotations>
      <Annotations xmlns="http://docs.oasis-open.org/odata/ns/edm" Target="ZDEMO_DDL_SPFLI_CDS.ZDEMO_DDL_SPFLIType/AirlineCode">
      <Annotation Term="Common.FieldControl" EnumMember="Common.FieldControlType/Mandatory"/>
      </Annotations>
      <Annotations xmlns="http://docs.oasis-open.org/odata/ns/edm" Target="ZDEMO_DDL_SPFLI_CDS.ZDEMO_DDL_SPFLIType/FlightConnectionNo">
      <Annotation Term="Common.FieldControl" EnumMember="Common.FieldControlType/Mandatory"/>
      </Annotations>
      <Annotations xmlns="http://docs.oasis-open.org/odata/ns/edm" Target="ZDEMO_DDL_SPFLI_CDS.ZDEMO_DDL_SPFLI_CDS_Entities/ZDEMO_DDL_SPFLI">
      <Annotation Term="Capabilities.FilterRestrictions">
      <Record>
      <PropertyValue Property="NonFilterableProperties">
      <Collection>
      <PropertyPath>Copy_ac</PropertyPath>
      </Collection>
      </PropertyValue>
      </Record>
      </Annotation>
      <Annotation Term="Capabilities.SortRestrictions">
      <Record>
      <PropertyValue Property="NonSortableProperties">
      <Collection>
      <PropertyPath>Copy_ac</PropertyPath>
      </Collection>
      </PropertyValue>
      </Record>
      </Annotation>
      </Annotations>
      <Annotations xmlns="http://docs.oasis-open.org/odata/ns/edm" Target="ZDEMO_DDL_SPFLI_CDS.ZDEMO_DDL_SFLIGHTType">
      <Annotation Term="Common.SemanticKey">
      <Collection>
      <PropertyPath>AirlineCode</PropertyPath>
      </Collection>
      </Annotation>
      </Annotations>
      <Annotations xmlns="http://docs.oasis-open.org/odata/ns/edm" Target="ZDEMO_DDL_SPFLI_CDS.ZDEMO_DDL_SPFLIType">
      <Annotation Term="Common.SemanticKey">
      <Collection>
      <PropertyPath>AirlineCode</PropertyPath>
      </Collection>
      </Annotation>
      </Annotations>
      <atom:link xmlns:atom="http://www.w3.org/2005/Atom" rel="self" href="http://vhcala4hci:50000/sap/opu/odata/sap/zdemo_ddl_spfli_cds/$metadata"/>
      <atom:link xmlns:atom="http://www.w3.org/2005/Atom" rel="latest-version" href="http://vhcala4hci:50000/sap/opu/odata/sap/zdemo_ddl_spfli_cds/$metadata"/>
      </Schema>
      </edmx:DataServices>
      </edmx:Edmx>

      But the error window opens

      Error%20Window

      Error Window

      When I noticed that a message comes in VSCODE status line
      XML Annotation Language Server: waiting for connection...
      I installed SAP Fiori Tools - XML Annotation Language Server

      This resolved LSP issue but got "problems"
      [Error: ENOENT: no such file or directory, open 'c:\webapp\manifest.json'] {
      errno: -4058,
      code: 'ENOENT',
      syscall: 'open',
      path: 'c:\\webapp\\manifest.json'
      }

      Moved myCSDL.metadata.xml to  webapp directory then got problem
      {"level":"info","message":"File 'file:///c%3A/Users/sssca/projects/cenproject1/webapp/myCSDL.metadata.xml' is not registered in manifest.json file"}

      {"level":"error","message":"Service component could not be initialized"}

      Regards
      Jayanta@Kolkata

      Author's profile photo Xiao-fei Song
      Xiao-fei Song
      Blog Post Author

      Hi Jayanta,

       

      CSDL modeler support opening file with *.edmx, *.edmx.xml, *.csdl.xml, *.metadata.xml extension.

       

      Regards,

      Xiao-fei

      Author's profile photo Jayanta Choudhuri
      Jayanta Choudhuri

      Hi Xiao-Fei

      The Open with CSDL Modeler comes with correct file extension.
      But throws an error window.

      I have updated my previous comment.
      As I have pasted the entire output of the CSDL file
      please try with this.

      Regards & Thanks
      Jayanta

      Author's profile photo Xiao-fei Song
      Xiao-fei Song
      Blog Post Author

      It was strange. I can open the csdl file successfully with the CSDL modeler. What exactly the error did you see? Are you using the latest version of the modeler?

      Author's profile photo Brian Watts
      Brian Watts

      Yes, thanks so much for developing this!!!!!

      Hoping you'll add support for SAP Business One's Service Layer. It also exposes an ODATA v4 endpoint with proper $metadata EDMX, but this Visual Studio Code tool gives me errors unfortunately.

      CsdlException: odatav4_metadata.edmx:13023 EntityType Error: Invalid Partner='ActivityType' for navigation property 'Activities'. Property 'ActivityType' in type 'SAPB1.Activity' is not a navigation property.
      
      <EntityType Name="ActivityType">...

      I tried editing and fixed some errors prior to this one (it seemed the generated EDMX had some weird spaces inside of the XML attributes). But, once I hit the error above, I started going down a bad worm hole

      *********************

      Later I tried loading my SAPB1 service layer EDMX into Microsoft's CsdlReader, like thus:

        string csdlFilePath = "odatav4_metadata_edmx_downloaded.xml";
        string csdl = System.IO.File.ReadAllText(csdlFilePath);
        IEdmModel model = CsdlReader.Parse(XElement.Parse(csdl).CreateReader());
      

      Then, I can get all the errors from it at one go, using TryWriteSchema, like this:

      System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create("cleaned.edmx");
      
      IEnumerable<Microsoft.OData.Edm.Validation.EdmError> errors;
      model.TryWriteSchema(writer, out  errors);
      
      if(errors != null)
      {
           foreach(var error in errors)
           {
              System.Console.WriteLine(error.ErrorMessage);
           }
       }
      
      writer.Flush();
      writer.Close();

       

      Here's what I got from doing that.. so.. I guess the way the SAP B1 Service Layer $metadata is implemented is not pefectly compliant


      The partner of the navigation property 'TransactionCode2' must not be the same property, and must point back to the navigation property.
      The partner of the navigation property 'PurchaseDeliveryNotes' must not be the same property, and must point back to the navigation property.
      The partner of the navigation property 'CorrectionPurchaseInvoiceReversal' must not be the same property, and must point back to the navigation property.
      The partner of the navigation property 'Drafts' must not be the same property, and must point back to the navigation property.
      The partner of the navigation property 'VendorPayments' must not be the same property, and must point back to the navigation property.
      The partner of the navigation property 'PaymentDrafts' must not be the same property, and must point back to the navigation property.
      The partner of the navigation property 'CreditNotes' must not be the same property, and must point back to the navigation property.
      The partner of the navigation property 'Invoices' must not be the same property, and must point back to the navigation property.
      The partner of the navigation property 'GoodsReturnRequest' must not be the same property, and must point back to the navigation property.
      The partner of the navigation property 'PurchaseRequests' must not be the same property, and must point back to the navigation property.
      The partner of the navigation property 'InventoryGenEntries' must not be the same property, and must point back to the navigation property.
      The partner of the navigation property 'Orders' must not be the same property, and must point back to the navigation property.
      The partner of the navigation property 'DeliveryNotes' must not be the same property, and must point back to the navigation property.
      The partner of the navigation property 'PurchaseDownPayments' must not be the same property, and must point back to the navigation property.
      The partner of the navigation property 'Returns' must not be the same property, and must point back to the navigation property.
      The partner of the navigation property 'CorrectionPurchaseInvoice' must not be the same property, and must point back to the navigation property.
      The partner of the navigation property 'CorrectionInvoice' must not be the same property, and must point back to the navigation property.
      The partner of the navigation property 'CorrectionInvoiceReversal' must not be the same property, and must point back to the navigation property.
      The partner of the navigation property 'PurchaseInvoices' must not be the same property, and must point back to the navigation property.
      .. truncated...