maskx / OData

easy access your database by OData WebApi
http://maskx.github.io/OData/
MIT License
15 stars 4 forks source link

More than one relationship between two entities #11

Open manuel-fernandez-rodriguez opened 3 years ago

manuel-fernandez-rodriguez commented 3 years ago

Hello, I was having a look at your library and I think found an issue when a table has more than one column referencing the same foreign table.

For my experiment, since the nuget package didn't seem to work for net core, I cloned your repository and added a new ASP Net Core WebAPI project referencing the library.

I used World Wide Importers sample database from Microsoft.

Then, I configured the datasource for the Sales schema:

var ds = new maskx.OData.SQLSource.SQLServer("Sales", "Data Source=.;Initial Catalog=WideWorldImporters;User ID=sa;PWD=******");
ds.Configuration.DefaultSchema = "Sales";

Had to solve a missing assembly reference to Microsoft.SQLServer.Types by directly referencing said nuget package from my WebAPI project. Got a warning on run, but it started to serve content.

I asked for [webroot]/sales/Customers and the response got cut off in the middle of the 1st customer's JSON data, but it was returning a 200 OK status (!)

So I did a select for a property with [webroot]/sales/Customers?$select=CustomerName, which correctly returned the 663 rows.

I also noticed this exception being caught, but not thrown during first request execution:

Microsoft.OData.ODataException: A property with name 'Customers' on type 'Sales.Customers' has kind 'None', but it is expected to be of kind 'Navigation'.

Then I knew it must be a property on Customers which was causing all my woes.

I went to the metadata URL to inspect the type definition, and I found several properties with the same name:

                [...]
                <NavigationProperty Name="Customers" Type="Collection(Sales.Customers)" Partner="Customers">
                    <ReferentialConstraint Property="CustomerID" ReferencedProperty="BillToCustomerID" />
                </NavigationProperty>
                <NavigationProperty Name="Customers" Type="Collection(Sales.Customers)" Partner="Customers" />
                [...]
                <NavigationProperty Name="People" Type="Collection(Application.People)" Partner="Customers" />
                <NavigationProperty Name="People" Type="Collection(Application.People)" Partner="Customers" />
                [...]
                <NavigationProperty Name="Cities" Type="Collection(Application.Cities)" Partner="Customers" />
                <NavigationProperty Name="Cities" Type="Collection(Application.Cities)" Partner="Customers" />
                [...]
                <NavigationProperty Name="Invoices" Type="Collection(Sales.Invoices)" Partner="Customers">
                    <ReferentialConstraint Property="CustomerID" ReferencedProperty="CustomerID" />
                </NavigationProperty>
                <NavigationProperty Name="Invoices" Type="Collection(Sales.Invoices)" Partner="Customers">
                    <ReferentialConstraint Property="CustomerID" ReferencedProperty="BillToCustomerID" />
                </NavigationProperty>

As displayed, there are several navigation properties with the same name, some of them with the same definition, some not.

I checked the particular case of cities in the sample database, and as expected, there were two foreign keys from Customers to Cities (DeliveryCityID and PostalCityID).

On the other hand, I was only able to find a single foreign key on Customers referencing itself (BillToCustomerID).

I hope all this information might help you to identify and solve this limitation, because I think this library can get to be really useful if it can address most normal circumstances found in a database, and having several foreign keys linking two tables is not an uncommon one.