2015-05-11 28 views
6

Sono nuovo di NHibernate che ha problemi con una mappatura. Non sono riuscito a rispondere a Google.HasMany relationship causa "Trovato riferimenti condivisi a una raccolta" durante la lettura dal db

mie entità simile a questa:

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(); 
    } 
} 

mie mappature simile a questa:

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); 
    } 
} 

L'idea è che Triage è un discriminatore scelto (SelectedDiscriminatorId) e discriminatore-tabella contiene la descrizione testi in diverse lingue disponibili. Non è particolarmente affezionato alla costruzione che Triage si riferisca a Discriminator with SelectedDiscriminatorId che è solo una parte della chiave composta in Discriminator (Id e LanguageId), ma è così che appare il mio database.

Così, quando ho Prendi il mio triages come questo:

_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); 

allora tutto funziona bene a condizione SelectedDiscriminatorId è univoco nel triages recuperati. Tuttavia, quando ci sono diversi triages con lo stesso SelectedDiscriminatorId, ottengo una HibernateException che dice "Informazioni aggiuntive: riferimenti trovati condivisi a una raccolta: TestProject.Triage.Discriminators" quando esegue l'istruzione session.Flush().

Qualche idea di cosa c'è che non va qui e di come lo correggo? Grazie.

Questo è come il database appare:

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

Puoi mostrare lo schema delle tabelle? – Najera

+0

Ho modificato la domanda per contenerlo. –

risposta

2

un modello di oggetti molto più sano sarebbe

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; } 
} 

con la mappatura

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(); 
    } 
} 

unico inconveniente è che lo SQL sarà un un po 'strano perché NHibernate pensa che il discriminatore esista da solo.

+0

La tua soluzione funziona bene e sono d'accordo che sembra più sano. Ma penso che sia più una soluzione alternativa che una vera soluzione al problema. –

+0

È una soluzione alternativa per lo schema presentato. Il modello Object va bene. La mappatura inviata ha anche molti problemi con l'aggiornamento e l'inserimento di triature che non dovrebbero esistere con la mappatura che ho postato. – Firo