Frage

Ich habe eine viele-zu-viele-Beziehung zwischen Fotos und tags: Ein Foto kann mehrere Tags haben und mehrere Fotos können die gleichen Tags teilen.

Ich habe eine Schleife, die die Fotos in einem Verzeichnis durchsucht und dann fügt sie NHibernate. Einige Tags werden zu den Fotos, die während dieses Prozesses, z.B. ein 2009-Tag, wenn das Foto im Jahr 2009.

genommen wird

Die Tag-Klasse implementiert Equals und GetHashCode und nutzt die Eigenschaft Namen als einzige Signatur-Eigenschaft. Sowohl Foto und Tag haben Ersatzschlüssel und versioniert werden.

Ich habe einige Code wie folgt:

public void Import() {
    ...
    foreach (var fileName in fileNames) {
        var photo = new Photo { FileName = fileName };
        AddDefaultTags(_session, photo, fileName);
        _session.Save(photo);
    }
    ...
}

private void AddDefaultTags(…) {
    ...
    var tag =_session.CreateCriteria(typeof(Tag))
                    .Add(Restriction.Eq(“Name”, year.ToString()))
                    .UniqueResult<Tag>();

    if (tag != null) {
        photo.AddTag(tag);
    } else {
        var tag = new Tag { Name = year.ToString()) };
        _session.Save(tag);
        photo.AddTag(tag);
    }
}

Mein Problem ist, wenn der Tag nicht existiert, zum Beispiel das erste Foto eines neuen Jahres. Die AddDefaultTags Methode überprüft, ob der Tag in der Datenbank vorhanden ist und schafft es dann und fügt sie NHibernate. Das funktioniert gut, wenn ein einzelnes Foto hinzugefügt, aber wenn mehrere Fotos im neuen Jahr zu importieren und in derselben Arbeitseinheit versagt es, da es immer noch nicht in der Datenbank vorhanden und wird wieder aufgenommen. Wenn die Arbeitseinheit abgeschlossen versagt es, da er versucht, zwei Einträge in der Tags-Tabelle mit dem gleichen Namen hinzufügen ...

Meine Frage ist, wie Sie sicherstellen, dass NHibernate nur versucht, einen einzigen Tag in der Datenbank in der obigen Situation zu schaffen. Brauche ich eine Liste der neu hinzugefügte Tags selbst erhalten oder kann ich das Mapping so hoch, dass es funktioniert?

War es hilfreich?

Lösung

Sie müssen _session.Flush() laufen, wenn Sie Ihre Kriterien nicht veraltete Daten zurückgeben sollte. Oder Sie sollten in der Lage sein, richtig zu tun, indem Sie die _session.FlushMode auf Auto einstellen.

Mit FlushMode.Auto, wird die Sitzung automatisch gespült werden, bevor die Kriterien ausgeführt wird.

EDIT: Und wichtig! Wenn Sie den Code Lesen Sie gezeigt haben, es sieht nicht, wie Sie eine Transaktion für die Einheit der Arbeit verwenden. Ich würde empfehlen, Ihre Arbeitseinheit in einer Transaktion Einwickeln - dass für FlushMode.Auto erforderlich ist, zu arbeiten, wenn Sie mit NH2.0 +

Lesen Sie hier weiter: NHibernate ISession Flush : Wo und wann es zu benutzen, und warum

Andere Tipps

Wenn Sie den neuen Tag wollen in der Datenbank zu sein, wenn Sie es jedes Mal überprüfen, müssen Sie die Transaktion begehen, nachdem Sie dort zu speichern setzen.

Ein weiterer Ansatz wäre die Tags in eine Sammlung zu lesen, bevor Sie die Fotos bearbeiten. Dann, wie Sie sagen, Sie lokale Suche würden und neue Tags nach Bedarf hinzufügen. Wenn Sie mit dem Ordner durchgeführt werden, können Sie die Sitzung begehen.

Sie sollten Ihre Zuordnungen schreiben, wie ich Ihre Frage nicht richtig verstanden haben.

Dies ist das typische „etwas sperren, die nicht da ist“ -Problem. Ich stand aber schon mehrmals und noch nicht über eine einfache Lösung für sie.

Das sind die Optionen, die ich weiß bis jetzt:

  • optimistisch: eine eindeutige Einschränkung auf den Namen und lassen Sie eine der Sitzungen verpflichten werfen auf. Dann sind Sie es erneut versuchen. Sie müssen sicherstellen, dass Sie nicht in einer Endlosschleife enden, wenn ein anderer Fehler auftritt.
  • Pessimistisch: Wenn Sie einen neuen Tag hinzufügen, können Sie sperren den gesamten Tag Tabelle TSQL mit
  • .
  • .NET Locking: Sie synchronisieren die Fäden .NET Sperren zu verwenden. Dies funktioniert nur, wenn Sie parallele Transaktionen im gleichen Prozess sind.
  • Stichworte erstellen eigene Sitzung (siehe unten)
  • mit

Beispiel:

public static Tag CreateTag(string name)
{
  try
  {
    using (ISession session = factors.CreateSession())
    {
      session.BeginTransaction();
      Tag existingTag = session.CreateCriteria(typeof(Tag)) /* .... */
      if (existingtag != null) return existingTag;
      {
        session.Save(new Tag(name));
      }
      session.Transaction.Commit();
    }
  }
  // catch the unique constraint exception you get
  catch (WhatEverException ex)
  {
    // try again
    return CreateTag(name);
  }
}

Das sieht einfach aus, hat aber einige Probleme. Sie erhalten immer einen Tag, das heißt entweder bestehende oder erstellt (und verpflichtet sofort). Aber der Tag, das Sie erhalten, ist aus einer anderen Sitzung, so wird es für Ihre Haupt-Sitzung getrennt. Sie müssen es Ihre Sitzung befestigen Kaskaden mit (die Sie wahrscheinlich nicht wollen,) oder zu aktualisieren.

-Tags Erstellen auf Ihre Haupt-Transaktion nicht mehr gekoppelt, dies war das Ziel, sondern bedeutet auch, dass alle erstellten Tags in der Datenbank zurück Ihre Transaktion rollen läßt. Mit anderen Worten: Tags schafft, ist nicht Teil der Transaktion mehr

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