9

Ho il seguente scenariocome raggiungere la tabella per classe concreta quando la classe base è astratta in fluente niberniato?

public abstract class BaseClass 
{ 
    public virtual int Id {get; set}; 
    public virtual string Name {get; set;} 
} 

public class FirstSubClass : BaseClass 
{ 
    //properties and behaviour here 
} 

public class SecondSubClass : BaseClass 
{ 
    //properties of SecondSubclass Here 
} 

public class ProcessStep 
{ 
    public virtual IList<BaseClass> ContentElements {get; set;} 
} 

per la mappatura ho utilizzato seguente frammento di codice: -

this._sessionFactory = 
          Fluently.Configure().Database(SQLiteConfiguration.Standard 
          .ConnectionString(@"Data Source=SqliteTestSqlDataAccess.s3db; Version=3; New=True; Pooling=True; Max Pool Size=1;")) 
          .Mappings(m => m.AutoMappings.Add(AutoMap.Assembly(assemblyWithDomainClasses).Conventions.Add(DefaultCascade.All()))) 
          .ExposeConfiguration(BuildSchema) 
          .BuildSessionFactory(); 

Per impostazione predefinita fluente ignorerà la classe base astratta che è BaseClass. Ma, come nella classe ProcessStep c'è contentelements proprietà che restituisce IList, io sono sempre un'eccezione: - NHibernate.MappingException: Associazione dei riferimenti alle classi non mappata: BaseClass

Se includo la classe di base utilizzando l'IncludeBase (typeof (BaseClass)) quindi funziona correttamente ma crea una tabella per classi BaseClass e Derivate e i record sono collegati con la relazione FK-PK (tabella per sottoclasse). Quello che voglio ottenere è tabella per classe di calcestruzzo. cioè ogni classe derivata avrà la propria tabella dove saranno presenti tutte le proprietà delle proprietà derivate di classe + nella classe base. Qualche idea su come ottenerlo?

risposta

9

Dato che non ho visto la tua mappatura, permettimi di fornire la mia. Si potrebbe raggiungere questo obiettivo facendo come questo

public class BaseClassMap:ClassMap<BaseClass> 
{ 
    public BaseClassMap() 
    { 
     /* 
     * Identity generator can't be native because subclass objects should be unique 
     * So use HiLo or Guid or other generators which will generate unique id on the child tables 
     */ 
     Id(x => x.Id).GeneratedBy.Guid(); 
     Map(x => x.Name); 
     UseUnionSubclassForInheritanceMapping(); // This is important - uses union-subclass mappings for the derived classes 
    } 
} 

public class FirstSubClassMap : SubclassMap<FirstSubClass> 
{ 
    public FirstSubClassMap() 
    { 
     Table("FirstSubClassTable"); 
     // Map properties for FirstSubClass 
    } 
} 

public class SecondSubClassMap : SubclassMap<SecondSubClass> 
{ 
    public SecondSubClassMap() 
    { 
     Table("SecondSubClassTable"); 
     // Map properties for SecondSubClass 
    } 
} 
+1

sto usando Automapping così, non ho la possibilità di mappare le classi separatamente. – Niraj

+0

puoi mescolare la mappatura automatica con mappature personalizzate, in modo che tu possa fornire il mapping solo per classi specifiche, il resto delle classi può essere mappato usando la mappatura automatica. Fluently.Configure (configurazione) .Mappings (cfg => {cfg.AutoMappings.Add (....); cfg..FluentMappings.AddFromAssembly (l'assieme di mappatura personalizzato);}) – Rajeesh

0

E mi ha fatto mal di testa per attuare la strategia di ereditarietà "Tabella per classe concreta" con una classe base astratta con automapping NHibernate. Ma penso, ho finalmente trovato una soluzione e voglio condividerla con te. Penso anche che non sia stato aggiunto ai documenti di automapping, perché è forse considerato un progetto di database "debole".

Prima qui ci sono alcune risorse che ho trovato su questo argomento: implementazione

Queste risorse fondamentalmente descrivere come è necessario farlo:

  1. Come già accennato, il fluente nibernito ignora le classi base astratte. Quindi è necessario aggiungerli esplicitamente.
// abstractBaseTypes is just a simple enumeration of base types 
// model is the AutoPersistenceModel 
abstractBaseTypes.ForEach(m => model = model.IncludeBase(m)); 
  1. a) Se si conoscono i tipi di base astratte in fase di compilazione è possibile utilizzare
//sets the union subclass strategy for the known base model 
model.Override<SuperType>(m => m.UseUnionSubclassForInheritanceMapping())) 
  1. b) Se non si conosce il tipo di cemento è possibile creare una sostituzione di mapping per ogni tipo base:
public class AbstractRightEntryMappingOverride : IAutoMappingOverride<AbstractRightEntry> 
{ 
    public void Override(AutoMapping<AbstractRightEntry> mapping) 
    { 
     mapping.UseUnionSubclassForInheritanceMapping(); 
    } 
} 

// You need to tell nhibernate where to find the overriden mappings. 
// You simply can add the assemblies again. 
modelAssemblies.ForEach(a => model = model.UseOverridesFromAssembly(a));