2015-05-11 15 views
6

Ich bin neu in NHibernate Probleme mit einem Mapping. Ich habe Google auf eine Antwort gescheitert.HasMany-Beziehung verursacht "Gefundene Referenzen auf eine Sammlung gefunden" beim Lesen von der db

Meine Entitäten wie folgt aussehen:

public class Triage 
{ 
    public virtual Guid Id { get; set; } 

    public virtual IDictionary<int, Discriminator> Discriminators { get; set; } 

    // This is to keep FluentNHibernate happy 
    public virtual int? SelectedDiscriminatorId { get; set; } 
} 

public class Discriminator 
{ 
    public virtual int Id { get; set; } 
    public virtual int LanguageId { get; set; } 

    public override bool Equals(object obj) 
    { 
     var other = obj as Discriminator; 
     if (ReferenceEquals(null, other)) return false; 
     if (ReferenceEquals(this, other)) return true; 

     return Id == other.Id && LanguageId == other.LanguageId; 
    } 

    public override int GetHashCode() 
    { 
     return new { Id, LanguageId }.GetHashCode(); 
    } 
} 

Meine Zuordnungen wie folgt aussehen:

public class TriageMap : ClassMap<Triage> 
{ 
    public TriageMap() 
    { 
     Id(x => x.Id).GeneratedBy.GuidComb(); 
     HasMany(x => x.Discriminators) 
      .KeyColumn("Id") 
      .PropertyRef("SelectedDiscriminatorId") 
      .Inverse() 
      .Cascade.All() 
      .Not.LazyLoad() 
      .AsMap(x => x.LanguageId); 

     // This mapping is only needed to keep FluentNHibernate happy... 
     Map(x => x.SelectedDiscriminatorId); 
    } 
} 

public class DiscriminatorMap : ClassMap<Discriminator> 
{ 
    public DiscriminatorMap() 
    { 
     CompositeId() 
      .KeyProperty(x => x.Id) 
      .KeyProperty(x => x.LanguageId); 
    } 
} 

Die Idee ist, dass Triage eine gewählte Diskriminatorfilter (SelectedDiscriminatorId) und der Diskriminator-Tabelle hat enthält die Beschreibung von Texte in mehreren verfügbaren Sprachen. Nicht besonders gern von der Konstruktion, die Triage auf Discriminator mit SelectedDiscriminatorId bezieht, die nur Teil des zusammengesetzten Schlüssels in Discriminator (Id und LanguageId) ist, aber so sieht meine Datenbank aus.

Also, wenn ich meine holen triages wie folgt aus:

_sessionFactory = CreateSessionFactory(); 
ISession session = _sessionFactory.OpenSession(); 
CurrentSessionContext.Bind(session); 
var triages = _sessionFactory 
    .GetCurrentSession() 
    .Query<Triage>() 
    .Fetch(t => t.Discriminators) 
    .ToList(); 
session.Flush(); 
session.Close(); 
CurrentSessionContext.Unbind(_sessionFactory); 

dann funktioniert alles in Ordnung bereitgestellt SelectedDiscriminatorId innerhalb der abgerufenen triages einzigartig ist. Wenn es mehrere Triages mit derselben SelectedDiscriminatorId gibt, erhalte ich jedoch eine HibernateException mit dem Zusatz "Zusätzliche Informationen: Gemeinsame Referenzen auf eine Sammlung gefunden: TestProject.Triage.Discriminators", wenn es die Anweisung session.Flush() ausführt.

Irgendeine Idee, was hier falsch ist und wie ich das korrigiere? Vielen Dank.

Dies ist, wie die Datenbank aussieht:

CREATE TABLE [dbo].[Triage](
    [Id] [uniqueidentifier] NOT NULL CONSTRAINT [DF_Triage_Id] DEFAULT (newid()), 
    [SelectedDiscriminatorId] [int] NULL, 
CONSTRAINT [PK_Triage] PRIMARY KEY CLUSTERED 
(
    [Id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

CREATE TABLE [dbo].[Discriminator](
    [ID] [int] NOT NULL, 
    [DisplayText] [nvarchar](255) NULL, 
    [LanguageID] [int] NOT NULL, 
    [Description] [nvarchar](4000) NULL, 
CONSTRAINT [PK_Discriminator] PRIMARY KEY CLUSTERED 
(
    [ID] ASC, 
    [LanguageID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
+0

Können Sie das Tabellenschema anzeigen? – Najera

+0

Ich habe die Frage bearbeitet, um das zu enthalten. –

Antwort

2

eine viel vernünftigere Objektmodell

public class Triage 
{ 
    public virtual Guid Id { get; set; } 

    public virtual Discriminator SelectedDiscriminator { get; set; } 

    // left out Equals and GetHashcode 
} 

public class Discriminator 
{ 
    public Discriminator() 
    { 
     LocalizedTexts = new Dictionary<int, string>(); 
    } 

    public virtual int Id { get; set; } 
    public virtual string Name 
    { 
     get 
     { 
      switch (Id) 
      { 
       case 1: 
        return "Discriminator A"; 
       case 2: 
        return "Discriminator B"; 
       case 3: 
        return "Discriminator C"; 
       default: 
        return "Unknown"; 
      } 
     } 
    } 
    public virtual IDictionary<int, LocalizedText> LocalizedTexts { get; protected set; } 

    public override bool Equals(object obj) 
    { 
     var other = obj as Discriminator; 

     return other != null && (Id == 0 ? ReferenceEquals(this, other) : Id == other.Id); 
    } 

    public override int GetHashCode() 
    { 
     return Id; 
    } 
} 

public class LocalizedText 
{ 
    public string DisplayName { get; set; } 
    public string Description { get; set; } 
} 

mit Mapping

public class TriageMap : ClassMap<Triage> 
{ 
    public TriageMap() 
    { 
     Id(x => x.Id).GeneratedBy.GuidComb(); 

     References(x => x.SelectedDiscriminator, "SelectedDiscriminatorId"); 
    } 
} 

public class DiscriminatorMap : ClassMap<Discriminator> 
{ 
    public DiscriminatorMap() 
    { 
     ReadOnly(); 
     SchemaExport.None(); // do not create Table for this. usefull for creating Schema for in memory unit-testing 
     Table("Discriminators"); 
     Where("LanguageId = <some value all discriminators have>"); 
     Id(x => x.Id).GeneratedBy.Assigned(); 

     HasMany(x => x.LocalizedTexts) 
      .Table("Discriminators") 
      .KeyColumn("Id") 
      .AsMap("LanguageId") 
      .Component(c => 
      { 
       c.Map(x => x.DisplayName); 
       c.Map(x => x.Description); 
      }) 
      .Cascade.AllDeleteOrphan() 
      .Not.LazyLoad(); 
    } 
} 

einzige Nachteil wäre, dass die SQL-a aussehen etwas komisch, weil NHibernate denkt, dass discriminator für sich existiert.

+0

Ihre Lösung funktioniert gut und ich stimme zu, dass es vernünftiger aussieht. Aber ich denke, es ist eher ein Workaround als eine tatsächliche Lösung des Problems. –

+0

Es ist eine Problemumgehung für das präsentierte Schema. Das Objektmodell ist in Ordnung. Ihr gepostetes Mapping hat auch eine Menge Probleme beim Aktualisieren und Einfügen von Triages, die mit dem von mir geposteten Mapping nicht existieren sollten. – Firo