Frage

Ich habe eine folgende Zuordnung:

<set name="People" lazy="true" table="ProjectPeople">
  <key column="ProjectId" />
  <composite-element class="PersonRole">
    <many-to-one name="Person" column="PersonId" cascade="save-update" not-null="true" />
    <many-to-one name="Role" column="RoleId" cascade="save-update" not-null="true"  />
  </composite-element>
</set>

Jetzt möchte ich nicht wirklich eine separate Klasse für die Rolle in der Domäne haben, ich brauche nur den Rollennamen. In DB -Rollen sollten jedoch immer noch auf eine separate Tabelle normalisiert werden Role (Id, Name).

Wie kann ich es so abbilden, dass die Leute die folgende Personenrolklasse verwenden?

public class PersonRole {
    public virtual Person Person { get; set; }
    public virtual string Role { get; set; }
}

Aktualisieren: Kopfgeld hinzugefügt, scheint eine Frage, die mir nicht nur nützlich ist.

War es hilfreich?

Lösung

Persönlich würde ich eine Rollenklasse wie Yassir schaffen

Wenn Sie jedoch die Struktur verwenden möchten, die Sie gerade haben, erstellen Sie eine Ansicht, die den ForiNGN -Schlüssel für Ihre Personentabelle und die Rollenbeschreibung enthält.

Ändern Sie die festgelegte Mapping -Tabelle so, dass Sie auf Ihre neue Ansicht hinweisen und Ihre Rollenzuordnung so ändern, dass es sich um eine Eigenschaft anstelle der vielen bis ein Mapping handelt.

Ich denke jedoch, dass Sie Ihre Rolle nicht aktualisieren können, da dies eine Ansicht wiedergibt.

Bearbeiten: Um die Rolle zu aktualisieren, die Sie hinzufügen können <sql-insert>,<sql-update> and <sql-delete> zu Ihrer Zuordnungsdatei, damit die Cascade-All funktioniert

Andere Tipps

Sie werden nicht die Antwort erhalten, auf die Sie sich hoffen, einfach weil sie nicht möglich ist. (N) Hibernate ist ein Objektrelationsrahmen und eine Unterstützung Drei Arten von Mapping Strategien:

  • Tabelle pro Klassenhierarchie
  • Tabelle pro Unterklasse
  • Tabelle pro Betonklasse

Es ermöglicht Ihnen auch, sich davon durch die Verwendung abzuweichen formula oder sql-insert usw., aber wie Sie herausgefunden haben, werden Sie am Ende nur mehr Schmerz verursachen, werden von der Hibernate -Community nicht gefördert und sind schlecht für die Wartbarkeit Ihres Codes.

Lösung?

Eigentlich ist es sehr einfach. Sie möchten keine Klasse für verwenden Role. Ich nehme an, Sie meinen, Sie wollen nicht entlarven eine Klasse von Typrolle und dass Sie nicht tippen müssen prObject.Role.Name die ganze Zeit. Gerade prObject.Role, was eine Zeichenfolge zurückgeben sollte. Sie haben mehrere Optionen:

  1. Verwenden Sie eine innere Klasse in beispielsweise PersonRole, diese Klasse kann intern oder privat sein. Fügen Sie eine Eigenschaftsrolle hinzu, die ein Mitglied des Mitglieds festlegt und aktualisiert.
  2. Verwenden Sie eine interne Klasse. Fügen Sie eine Eigenschaftsrolle hinzu, die ein Mitglied des Mitglieds festlegt und aktualisiert.

Lassen Sie uns Option 2 untersuchen:

// mapped to table Role, will not be visible to users of your DAL
// class can't be private, it's on namespace level, it can when it's an inner class
internal class Role 
{
    // typical mapping, need not be internal/protected when class is internal
    // cannot be private, because then virtual is not possible
    internal virtual int Id { get; private set; }
    internal virtual string Name { get; set; }
}

// the composite element
public class PersonRole
{
    // mapped properties public
    public virtual Person Person { get; set; }

    // mapped properties hidden
    internal virtual Role dbRole { get; set; }

    // not mapped, but convenience property in your DAL
    // for clarity, it is actually better to rename to something like RoleName
    public string Role     /* need not be virtual, but can be */
    { 
        get
        {
            return this.dbRole.Name;
        }
        set
        {
            this.dbRole.Name = value;    /* this works and triggers the cascade */
        }
    }
}

Und die Zuordnung kann wie erwartet aussehen. Ergebnis: Sie haben die Regel der Ein-Tisch-per-Klasse-Regel nicht verletzt (EDIT: ASKER sagt, dass er ausdrücklich gegen diese Regel verstoßen möchte, und Hib unterstützt sie, was korrekt ist), aber Sie haben die Objekte vor Änderungen und Zugriff versteckt, indem Sie typische objektorientierte Techniken verwenden. Alle NH -Funktionen (Kaskade usw.) funktionieren immer noch wie erwartet.

(N) Helberate dreht sich alles um diese Art von Entscheidungen: Wie man eine gut durchdacht und sichere Abstraktionsschicht in Ihre Datenbank macht, ohne Klarheit, Kürze oder Wartbarkeit zu beeinträchtigen oder die OO- oder ORM-Regeln zu verletzen.


Update (nach q. War geschlossen)

Andere hervorragende Ansätze, die ich beim Umgang mit dieser Art von Problem viel verwende, sind:

  • Erstellen Sie Ihre Zuordnungen normal (dh eine Klassen pro Tisch, ich weiß, dass es Ihnen nicht gefällt, aber es ist für die besten) und verwenden Sie Erweiterungsmethoden:

     // trivial general example
     public static string GetFullName(this Person p)
     {
         return String.Format("{0} {1}", p.FirstName, p.LastName);
     }
    
     // gettor / settor for role.name
     public static string GetRoleName(this PersonRole pr)
     {
         return pr.Role == null ? "" : pr.Role.Name;
     }
     public static SetRoleName(this PersonRole pr, string name)
     {
         pr.Role = (pr.Role ?? new Role());
         pr.Role.Name = name;
     }
    
  • Erstellen Sie Ihre Zuordnungen normal, verwenden Sie aber partial classES, die es Ihnen ermöglichen, Ihre Klasse auf jeden Weg zu "dekorieren". Der Vorteil: Wenn Sie generierte Zuordnungen Ihrer Tabellen verwenden, regeneriert Sie so oft, wie Sie möchten. Natürlich sollten die Teilklassen in separate Dateien eingehen. In Anbetracht des Wunsches, "Aufblähen" zu vermeiden, ist dies wahrscheinlich kein gutes Szenario.

     public partial class PersonRole
     {
         public string Role {...}
     }
    
  • Vielleicht einfachste: Nur Überlastung ToString() zum Role, was es für den Einsatz in den Gebrauch in String.Format Und Freunde, aber natürlich macht es nicht zuweisbar. Standardmäßig sollte jede Entitätsklasse oder POCO a haben ToString() Überlastung sowieso.

Obwohl es möglich ist, dies direkt mit Nhibernate zu tun, ist das q. wurde geschlossen, bevor ich Zeit hatte, es mir anzusehen (niemand hatte Schuld, ich hatte einfach keine Zeit). Ich werde aktualisieren, wenn ich die Zeit finde, dies durch Hibernate -HBM -Mapping zu tun, obwohl ich dem Ansatz nicht zustimme. Es ist nicht gut, mit fortgeschrittenen HIB -Konzepten zu ringen, wenn das Endergebnis für andere Programmierer weniger klar ist und insgesamt weniger klar ist Best Practices von Nhibernate und S#ARP). Die Übung ist jedoch dennoch interessant.

In Anbetracht der Kommentare zu "Best Practices": In typischen Situationen sollte es nicht nur "eine Klasse pro Tabelle" sein, sondern auch eine Idaoxxx, eine Daoconcretexxx und eine getdaoxxx für jede Tabelle, in der Sie die Klasse/Schnittstelle hierarchy verwenden, um zwischen Differenzieren Lese- und Lese-/Schreibtabellen. Das sind mindestens vier Klassen/Codezeilen pro Tabelle. Dies ist in der Regel automatisch generiert, bietet jedoch eine sehr klare Zugriffsschicht (DAO) für Ihre Datenschicht (DAL). Die Datenschicht ist am besten so spartanisch wie möglich. Nicht Role.Name hinein Role.

Diese sind am besten Allgemeines Praktiken Methoden Ausübungen. Es ist nicht immer möglich oder machbar oder sogar in bestimmten speziellen oder typischen Standationen notwendig.

Ich denke nicht, dass es möglich ist, viele zu einem primitiven Typ zuzuordnen, wenn ich Sie wäre, würde ich dem Modell eine Rollenklasse hinzufügen

Dies ist die größte Ausschaltung des gesamten oo puristischen Ding. Sicherlich ist es das Ziel, eine Arbeitsanwendung zu haben. Nicht irgendeine Version einer perfekten Klassenhierarchie. Was ist also, wenn Sie "probject.role.name" anstelle von "probject.role" codieren müssen. Wie hilft Ihnen dies, ein besseres zuverlässigeres Programm zu machen?

Aus dem Anwendungsdesign ist puristische Sicht, was Sie wollen, einfach falsch. Eine Person kann mehrere Rollen spielen, eine Rolle kann normalerweise mehreren Personen zugewiesen werden. Warum sollten Sie all diese Schwierigkeiten einsetzen, um eine unrealistische Rolle pro Person Klasse Hierachy durchzusetzen, wenn das nicht löste Datenmodell viele Rollen pro Person spielt?

Wenn Sie wirklich eine Regel "nur eine Rolle pro Person" haben, sollte sie im zugrunde liegenden Datenmodell reflektiert werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top