2017-10-10 38 views
0

Je souhaite créer une classe de base pour certaines de mes entités, puisqu'elles partagent toutes une propriété de liste Event. Je veux également faire la Event liste une propriété readonly.Fluent NHibernate Mappe correctement la propriété readonly de la classe de base

J'ai donc créé une classe de base EventRelatedEntity, puis je l'ai dérivée sur chacune de mes classes d'entités relatives aux événements.

Veuillez également noter que la classe EventRelatedEntity n'a pas de classe de mappage NHibernate car elle n'est pas liée à une table.

Voir le code ci-dessous.

Classe de base:

public class EventRelatedEntity 
{ 
    private readonly List<Event> events; 

    public virtual IReadOnlyCollection<Event> Events { get; protected set; } 

    public EventRelatedEntity() 
    { 
     events = new List<Event>(); 
     Events = events.AsReadOnly(); 
    } 

    protected virtual void AddEvent<T>(T entity, string message) 
    { 
     if (events == null) 
      events = new List<Event>(); 

     Event newEvent = new Event(); 

     if (typeof(T) == typeof(Company)) 
     { 
      newEvent.CompanyId = (entity as Company).Id; 
      // ...and do some other stuff... 
     } 
     else if (typeof(T) == typeof(Document)) 
     { 
      newEvent.DocumentId = (entity as Document).Id; 
      // ...and do some other stuff... 
     } 
     else if (typeof(T) == typeof(Typology)) 
     { 
      newEvent.TypologyId = (entity as Typology).Id; 
      // ...and do some other stuff... 
     } 

     newEvent.Message = message; 

     events.Add(newEvent); 
    } 
} 

classes d'entité

public class Company : EventRelatedEntity 
{ 
    [Key] 
    public virtual int Id { get; protected set; } 
    [Required] 
    public virtual string Alias { get; set; } 
    [Required] 
    public virtual string CompanyName { get; set; } 
    // ...and some other properties... 

    #region Actions 

    public virtual void AddEvent(string message) 
    { 
     base.AddEvent(this, message); 
    } 

    #endregion 
} 

public class Document : EventRelatedEntity 
{ 
    [Key] 
    public override int Id { get; protected set; } 
    [Required] 
    public virtual User User { get; protected set; } 
    // ...and some other properties... 

    #region Actions 

    public virtual void AddEvent(string message) 
    { 
     base.AddEvent(this, message); 
    } 

    #endregion 
} 

// ...and some other classes... 

classes de cartographie Fluent NHibernate pour les entités

public class CompanyMap : ClassMap<Company> 
{ 
    public CompanyMap() 
    { 
     Table("Companies"); 
     LazyLoad(); 
     Id(x => x.Id).GeneratedBy.Identity().Column("Id"); 
     Map(x => x.Alias).Column("Alias").Not.Nullable(); 
     Map(x => x.CompanyName).Column("CompanyName").Not.Nullable(); 
     // ...and some other mappings... 

     // Link with Events table 
     HasMany(x => x.Events) // Events is declared in the base class (EventRelatedEntity) 
      .KeyColumn("CompanyId") 
      .Access.LowerCaseField() 
      .Cascade.AllDeleteOrphan(); 
    } 
} 

public class DocumentMap : ClassMap<Document> 
{ 
    public DocumentMap() 
    { 
     Table("Documents"); 
     LazyLoad(); 
     Id(x => x.Id).GeneratedBy.Identity().Column("Id"); 
     References(x => x.User).Column("UserId"); 
     // ...and some other mappings... 

     // Link with Events table 
     HasMany(x => x.Events) // Events is declared in the base class (EventRelatedEntity) 
      .KeyColumn("DocumentId") 
      .Access.LowerCaseField() 
      .Cascade.AllDeleteOrphan(); 
    } 
} 

// ...and some other mapping classes... 

Enfin, je veux éviter l'accès direct à la méthode List<>.Add(). Je veux une collection en lecture seule. La seule façon d'ajouter un nouveau Event à la liste des événements d'une entité doit être la méthode AddEvent de la classe d'entité correspondante.

Exemple:

Document document = session.Get<Document>(1); 
// ...the same for other derived classes... 

// I WANT TO AVOID THIS! 
document.Events.Add(new Event()); 
// WANTS TO BE THE ONLY PERMITTED WAY TO ADD NEW EVENTS 
document.AddEvent("My new event message"); 

Le problème est que quand je fais le:

Document document = session.Get<Document>(1); 

je reçois une erreur de NHibernate:

Cannot cast objects of type 'NHibernate.Collection.Generic.PersistentGenericBag'1 [SolutionDOC_Interface.Entity.Event]' to the 'System.Collections.Generic.List'1 [SolutionDOC_Interface.Entity.Event]' type.

Je pense qu'il est lié à la En fait, la classe EventRelatedEntity n'a pas de mappage NHibernate, mais je ne peux pas fournir de carte car elle ne doit pas o avec une table en DB. Peut-être que si je déclare la liste des événements à l'intérieur de chaque classe (Société, Document, etc.) sans utiliser l'héritage, NHibernate fonctionnera, mais cette approche produirait pas mal de duplication de code que je veux éviter.

MISE À JOUR 2017/10/18

Après avoir modifié le code comme @ryan suggéré, maintenant il fonctionne.

Revised Code:

public class EventRelatedEntity 
{ 
    private readonly IList<Event> events; 

    public virtual IReadOnlyCollection<Event> Events { get; protected set; } 

    public EventRelatedEntity() 
    { 
     events = new List<Event>(); 
     Events = (events as List<Event>).AsReadOnly(); 
    } 

    // ... 
} 
+0

donc ce qui est le problème? Si 'Events' est bien déclaré comme' IReadOnlyCollection', alors 'document.Events.Add (new Event())' devrait produire une erreur: '' IReadOnlyCollection 'ne contient pas de définition pour' Ajouter '. .' – ryan

+0

Je reçois une erreur NHibernate. J'ai mis à jour la question. –

Répondre

1

Utilisez l'interface de liste au lieu de la classe de liste concrète, le casting de NHibernate.Collection.Generic.PersistentGenericBag devrait fonctionner.

utilisation IList<Event> au lieu de List<Event> si EventRelatedEntity devient:

public class EventRelatedEntity 
{ 
    private readonly IList<Event> events; 

    // rest of implementation... 
}