2009-03-23 13 views
31

Ich bin gerade auf Fluent NHibernate und ich habe ein Problem festgestellt und habe keine Informationen darüber gefunden.Fluent NHibernate, arbeiten mit Schnittstellen

Hier ist der Fall:

public class Field : DomainObject, IField 
{ 
    public Field() 
    { 
    } 

    public virtual string Name { get; set; } 
    public virtual string ContactPerson { get; set; } 
    public virtual bool Private { get; set; } 
    public virtual IAddress Address { get; set; } 
} 

iAddress ist eine Schnittstelle, durch eine Klasse mit dem Namen Adresse implementiert

public class Address : DomainObject, IAddress 
{ 
    public Address() 
    { 
    } 

    public virtual string City { get; set; } 
    public virtual string Country { get; set; } 
    public virtual string PostalCode { get; set; } 
    public virtual string StreetAddress { get; set; } 
} 

für beide Klassen

meine Mapping-Dateien Hier ist

ADDRESS

public class AddressMap : ClassMap<Address> 
{ 
    public AddressMap() 
    { 
     WithTable("Addresses"); 
     Id(x => x.Id, "Id").Access.AsCamelCaseField(Prefix.Underscore).GeneratedBy.Guid(); 
     Map(x => x.City, "City"); 
     Map(x => x.Country, "Country"); 
     Map(x => x.PostalCode, "PostalCode"); 
     Map(x => x.StreetAddress, "StreetAddress"); 
    } 
} 

FIELD

public class FieldMap : ClassMap<Field> 
{ 
    public FieldMap() 
    { 
     WithTable("Fields"); 
     Id(x => x.Id, "Id").Access.AsCamelCaseField(Prefix.Underscore).GeneratedBy.Guid(); 
     Map(x => x.Name, "Name"); 
     Map(x => x.ContactPerson, "ContactPerson"); 
     Map(x => x.Private, "Private"); 
     References(x => x.Address, "AddressId").Cascade.Delete().Cascade.SaveUpdate(); 
    } 
} 

Wenn ich also ein Feldobjekt aus meiner Datenbank retrive versucht, erhalte ich einen NHibernate Fehler, der besagt, dass iAddress nicht abgebildet wird. Gibt es eine Möglichkeit, NHibernate anzugeben, die Address-Klasse im Mapping zu verwenden?

Bitte lassen Sie mich wissen, wenn weitere Informationen benötigt werden.

Vielen Dank,

Charles

+0

Wie modellierst du die IAddress-Hierarchie in der Datenbank? Tabelle-pro-Hierarchie (eine Tabelle, die alle Arten von Adresse enthält) oder Tabelle-für-konkrete-Klasse? Sie haben angegeben, dass Sie auf Fluent umgestiegen sind. Daher könnte die Veröffentlichung eines XML-Mappings helfen, zu bestimmen, was Sie erreichen möchten. –

+0

In der Tat wechselte ich von ADO.NET Entity Framework zu Nhibernate mit Fluent NHibernate. In meiner Datenbank gibt es eine Tabelle, die alle Arten von Adressen enthält. Übrigens, ich habe beschlossen, diese Schnittstellen zu entfernen, erkannte ich, dass es nutzlos war. Aber ich denke, die Frage ist immer noch gültig. Danke, Charles –

Antwort

35

Ich finde, dass es gute Gründe gibt, eine Schnittstelle anstelle einer konkreten Klasse als Eigenschaft zu verwenden.

Zum Beispiel, wenn Ihre Field-Klasse in einem separaten Projekt für die Address-Klasse war und Sie vom Projekt der Field-Klasse keine Abhängigkeit vom Projekt der Address-Klasse hatten.

Es gibt andere Möglichkeiten, mit dieser Situation umzugehen, aber der einfachste Weg besteht oft darin, zu versuchen, was Sie tun und der NHibernate die konkrete Klasse, die sie für IAddress verwenden soll, zu erklären.

können Sie jetzt tun dies in Fluent NHibernate, wie folgen aus:

References(x => x.Address, "AddressId") 
    .Class(typeof(Address); 

Leider können Sie diese mit HasMany oder HasManyToMany nicht tun. Ich bin mir nicht sicher, ob dies überhaupt möglich wäre, weil in C# keine gute Kovarianz unterstützt wird.

+26

** Update: ** können Sie 'Referenzen verwenden

(x => x.Address) .Column ("AddressId");' Sie können das gleiche tun mit 'HasMany' und 'HasManyToMany' durch Hinzufügen des generischen Typparameters. – Jay

+0

+1 für das Update, genau das, was ich gesucht habe, vielen Dank. – 4imble

+0

Vielen Dank, genau das, was ich auch gesucht habe ... versuchte .CollectionType() angekettet an meinem HasMany(), aber das schien nicht zu funktionieren. – calebt

5

auf Ihrem Field-Objekt, haben Sie ein Objekt vom Typ iAddress. Dies könnte durch eine Anzahl von verschiedenen Implementierungen implementiert werden. Mit dem, was Sie gefragt haben, würde jede Implementierung ihre eigene Zuordnung haben, die eine Reihe von Schwierigkeiten (Unmöglichkeiten?) Für NHibernate einführen würde.

Ein einfaches Beispiel würde helfen, zu demonstrieren. Angenommen, Sie haben zwei IAddress-Implementierungen Address1 und Address2. Sie sind jeweils in einer eigenen Tabelle, tblAddress1 und tblAddress2, gespeichert. Wenn Sie versuchen, Ihr Field-Objekt zu laden, wissen alle NHibernate, dass Sie etwas haben, das IAddress implementiert, es weiß nicht, welche Implementierung beibehalten wurde. Woher weiß es, mit welcher Zuordnung das untergeordnete Objekt für ein bestimmtes Feld abgerufen werden soll?

Ich bin sicher, es gibt mehr Komplikationen, aber dieses Beispiel zeigt, warum Sie eine Zuordnung für den genauen Typ des Objekts haben müssen, das Sie deklariert haben.

0

Wenn Sie Ihr ORM vollständig von Ihrer Domänenebene entkoppeln und auf Schnittstellen in Ihrer Datenschicht referenzieren möchten, anstatt konkrete Klassen anzugeben, können Sie einen EmptyInterceptor implementieren, um eine Zuordnung zwischen den beiden zu erstellen.

Siehe meine Antwort here.