Ich versuche, ein einfaches Spielzeugprojekt mit Entity Framework, WebAPI, OData und einem Angular-Client zusammenzustellen. Alles funktioniert gut, außer dass die Navigationseigenschaft, die ich auf eines meiner Modelle gesetzt habe, nicht funktioniert. Wenn ich meine API mit $ expand aufrufen, haben die zurückgegebenen Entitäten ihre Navigationseigenschaften nicht.OData und WebAPI: Navigationseigenschaft nicht vorhanden auf Modell
sind meine Klassen Hund und Besitzer, und sehen wie folgt aus:
public class Dog
{
// Properties
[Key]
public Guid Id { get; set; }
public String Name { get; set; }
[Required]
public DogBreed Breed { get; set; }
public int Age { get; set; }
public int Weight { get; set; }
// Foreign Keys
[ForeignKey("Owner")]
public Guid OwnerId { get; set; }
// Navigation
public virtual Owner Owner { get; set; }
}
public class Owner
{
// Properties
public Guid Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
public DateTime SignupDate { get; set; }
// Navigation
public virtual ICollection<Dog> Dogs { get; set; }
}
Ich habe Abfrage mein Hund Controller einrichten zu handhaben auch:
public class DogsController : ODataController
{
DogHotelAPIContext db = new DogHotelAPIContext();
#region Public methods
[Queryable(AllowedQueryOptions = System.Web.Http.OData.Query.AllowedQueryOptions.All)]
public IQueryable<Dog> Get()
{
var result = db.Dogs.AsQueryable();
return result;
}
[Queryable(AllowedQueryOptions = System.Web.Http.OData.Query.AllowedQueryOptions.All)]
public SingleResult<Dog> Get([FromODataUri] Guid key)
{
IQueryable<Dog> result = db.Dogs.Where(d => d.Id == key).AsQueryable().Include("Owner");
return SingleResult.Create(result);
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
Ich habe die Datenbank mit einem ausgesät Bit der Beispieldaten. Alle Hundedatensätze haben eine Eigentümer-ID, die mit der ID eines Eigentümers in der Tabelle Besitzer übereinstimmt.
für die Liste der Hunde Abfragen dies mit adaequat:
http://localhost:49382/odata/Dogs
ich eine Liste von Hunde-Einheiten erhalten, ohne dass die Eigentümer Navigationseigenschaft.
Abfragen für die Hunde mit ihren Besitzern OData $ mit expand nicht funktioniert:
http://localhost:49382/odata/Dogs?$expand=Owner
Meine Antwort ist ein 200 mit all den Hundeeinheiten, aber keiner von ihnen eine Owner-Eigenschaft haben auf sie in der JSON.
Wenn ich meine Metadaten abfragen, finde ich, dass OData darüber zu wissen scheint:
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
<edmx:DataServices>
<Schema Namespace="DogHotelAPI.Models" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityType Name="Dog">
<Key>
<PropertyRef Name="id" />
</Key>
<Property Name="id" Type="Edm.Guid" Nullable="false" />
<Property Name="name" Type="Edm.String" />
<Property Name="breed" Type="DogHotelAPI.Models.Enums.DogBreed" Nullable="false" />
<Property Name="age" Type="Edm.Int32" Nullable="false" />
<Property Name="weight" Type="Edm.Int32" Nullable="false" />
<Property Name="ownerId" Type="Edm.Guid" />
<NavigationProperty Name="owner" Type="DogHotelAPI.Models.Owner">
<ReferentialConstraint Property="ownerId" ReferencedProperty="id" />
</NavigationProperty>
</EntityType>
<EntityType Name="Owner">
<Key>
<PropertyRef Name="id" />
</Key>
<Property Name="id" Type="Edm.Guid" Nullable="false" />
<Property Name="name" Type="Edm.String" />
<Property Name="address" Type="Edm.String" />
<Property Name="phone" Type="Edm.String" />
<Property Name="signupDate" Type="Edm.DateTimeOffset" Nullable="false" />
<NavigationProperty Name="dogs" Type="Collection(DogHotelAPI.Models.Dog)" />
</EntityType>
</Schema>
<Schema Namespace="DogHotelAPI.Models.Enums" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EnumType Name="DogBreed">
<Member Name="AfghanHound" Value="0" />
<Member Name="AmericanStaffordshireTerrier" Value="1" />
<Member Name="Boxer" Value="2" />
<Member Name="Chihuahua" Value="3" />
<Member Name="Dachsund" Value="4" />
<Member Name="GermanShepherd" Value="5" />
<Member Name="GoldenRetriever" Value="6" />
<Member Name="Greyhound" Value="7" />
<Member Name="ItalianGreyhound" Value="8" />
<Member Name="Labrador" Value="9" />
<Member Name="Pomeranian" Value="10" />
<Member Name="Poodle" Value="11" />
<Member Name="ToyPoodle" Value="12" />
<Member Name="ShihTzu" Value="13" />
<Member Name="YorkshireTerrier" Value="14" />
</EnumType>
</Schema>
<Schema Namespace="Default" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityContainer Name="Container">
<EntitySet Name="Dogs" EntityType="DogHotelAPI.Models.Dog">
<NavigationPropertyBinding Path="owner" Target="Owners" />
</EntitySet>
<EntitySet Name="Owners" EntityType="DogHotelAPI.Models.Owner">
<NavigationPropertyBinding Path="dogs" Target="Dogs" />
</EntitySet>
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
Was könnte ich das fehlt, ist meine Navigation preoprty verhindert mit dem Rest meines Modells kommen zurück?
EDIT
weiter Um das Problem, das ich auf der Server-Seite einschließlich der Eigentümer in C# versucht zu isolieren. Ich habe diese Zeile in der Get-Methode meiner Hunde Controller:
var test = db.Dogs.Include("Owner").ToList();
Damit ich debuggen können und sehen, dass die damit verbundenen Besitzer enthalten sind. Jeder Hund hat den Besitzer, der ihm in dieser Liste zugeordnet ist.
Die Verwendung von .Include ("Besitzer") auf, was tatsächlich zurückgegeben wird, behebt das Problem nicht - die Eigenschaften erreichen immer noch nicht den Client.
Dies scheint zu bedeuten, dass die Navigationseigenschaften funktionieren, aber nicht zurück zum Client gesendet werden. Es scheint, als ob die Wunde auf ein Problem mit OData oder WebAPI hinweist, würde ich schätzen, aber ich bin mir nicht sicher was.
Außerdem habe ich die folgenden Zeilen Application_Start in meinem Global.asax-Datei, um zu handhaben Kreisnavigationseigenschaften hinzugefügt:
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling =
Newtonsoft.Json.PreserveReferencesHandling.All;
Ich habe das eine kreisförmige Referenz im Falle war irgendwie der Täter, aber diese ändert nichts.
UPDATE
Ich bemerkte, dass ein Aufruf an
http://localhost:49382/odata/Dogs(abfd26a5-14d8-4b14-adbe-0a0c0ef392a7)/owner
Arbeiten zu machen. Dies ruft den Besitzer dieses Hundes ab. Dies zeigt weiter, dass meine Navigationseigenschaften korrekt eingerichtet sind, nur werden nicht in Antworten auf Aufrufe mit $ expand enthalten.
UPDATE 2
Hier ist das Register Methode meiner WebApiConfig Datei:
public static void Register(HttpConfiguration config)
{
//config.Routes.MapHttpRoute(
// name: "DefaultApi",
// routeTemplate: "api/{controller}/{id}",
// defaults: new { id = RouteParameter.Optional }
//);
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EnableLowerCamelCase();
builder.EntitySet<Dog>("Dogs");
builder.EntitySet<Owner>("Owners");
config.EnableQuerySupport();
config.MapODataServiceRoute(
routeName: "ODataRoute",
routePrefix: "odata",
model: builder.GetEdmModel());
// Uncomment the following line of code to enable query support for actions with an IQueryable or IQueryable<T> return type.
// To avoid processing unexpected or malicious queries, use the validation settings on QueryableAttribute to validate incoming queries.
// For more information, visit http://go.microsoft.com/fwlink/?LinkId=279712.
//config.EnableQuerySupport();
// To disable tracing in your application, please comment out or remove the following line of code
// For more information, refer to: http://www.asp.net/web-api
config.EnableSystemDiagnosticsTracing();
}
In Tests auf meinem eigenen funktionalen OData v4-Setup. Ich habe festgestellt, dass durch das Einfügen des Includes ("RelatedEntity") auch die zugehörige Entität nicht zurückgegeben wurde. Ich versuchte zu untersuchen, wie der $ expand-Befehl debuggt wird, sobald er an die API übergeben wurde, konnte die Informationen jedoch nicht finden. Ich würde vorschlagen, wenn es möglich ist, das Gerüst zu verwenden, das mit Visual Studio zur Verfügung gestellt wird, um einen Besitzer- und Hundecontroller zu erzeugen. Passen Sie Ihre [Queryable] an Ihre Anforderungen an, indem Sie die erzeugten generischen Daten verwenden, und versuchen Sie es auf diese Weise, wenn dies überhaupt möglich ist. – Pynt
Ich denke immer noch, dass es nur an die Navigationseigenschaft und Fremdschlüsseleinstellung gebunden sein kann. Versuchen Sie möglicherweise eine OData-Abfrage in einer separaten Klasse mit einem Unterbrechungspunkt, um festzustellen, ob Sie beide Datenpunkte abrufen können, um zu überprüfen, ob die Beziehung mithilfe einer generischen Entitätsabfrage eingerichtet wurde. – Pynt