2010-04-13 13 views
5

Nella mia ricerca per un filtro database della versione a livello di un'applicazione, ho scritto il seguente codice:Qual è il modo migliore per fornire un AutoMappingOverride per un'interfaccia in automapper fluentnhibernate

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using FluentNHibernate.Automapping; 
using FluentNHibernate.Automapping.Alterations; 
using FluentNHibernate.Mapping; 
using MvcExtensions.Model; 
using NHibernate; 

namespace MvcExtensions.Services.Impl.FluentNHibernate 
{ 
    public interface IVersionAware 
    { 
     string Version { get; set; } 
    } 

    public class VersionFilter : FilterDefinition 
    { 
     const string FILTERNAME = "MyVersionFilter"; 
     const string COLUMNNAME = "Version"; 

     public VersionFilter() 
     { 
      this.WithName(FILTERNAME) 
       .WithCondition("Version = :"+COLUMNNAME) 
       .AddParameter(COLUMNNAME, NHibernateUtil.String); 
     } 

     public static void EnableVersionFilter(ISession session,string version) 
     { 
      session.EnableFilter(FILTERNAME).SetParameter(COLUMNNAME, version); 
     } 

     public static void DisableVersionFilter(ISession session) 
     { 
      session.DisableFilter(FILTERNAME); 
     } 
    } 

    public class VersionAwareOverride : IAutoMappingOverride<IVersionAware> 
    { 
     #region IAutoMappingOverride<IVersionAware> Members 

     public void Override(AutoMapping<IVersionAware> mapping) 
     { 
      mapping.ApplyFilter<VersionFilter>(); 
     } 
     #endregion 
    } 

} 

Ma, dal momento che le sostituzioni non funzionano su interfacce, sto cercando un modo per implementarlo. Attualmente sto usando in questo modo (piuttosto ingombrante) per ogni classe che implementa l'interfaccia:

public class SomeVersionedEntity : IModelId, IVersionAware 
{ 
    public virtual int Id { get; set; } 
    public virtual string Version { get; set; } 
} 

public class SomeVersionedEntityOverride : IAutoMappingOverride<SomeVersionedEntity> 
{ 
    #region IAutoMappingOverride<SomeVersionedEntity> Members 

    public void Override(AutoMapping<SomeVersionedEntity> mapping) 
    { 
     mapping.ApplyFilter<VersionFilter>(); 
    } 

    #endregion 
} 

Sono stato a guardare IClassmap interfacce, ecc, ma non sembrano fornire un modo per accedere al metodo ApplyFilter quindi non ne ho avuto la minima idea ...

Dato che probabilmente non sono il primo ad avere questo problema, sono abbastanza sicuro che dovrebbe essere possibile; Sono solo non del tutto sicuro di come questo funziona ..

EDIT: Ho acquistato un po 'più vicino ad una soluzione generica:

Questo è il modo in cui ho cercato di risolverlo:

Utilizzando una classe generica di attuare modifiche alle classi di attuazione un'interfaccia:

public abstract class AutomappingInterfaceAlteration<I> : IAutoMappingAlteration 
{ 
    public void Alter(AutoPersistenceModel model) 
    { 
     model.OverrideAll(map => 
     { 
      var recordType = map.GetType().GetGenericArguments().Single(); 
      if (typeof(I).IsAssignableFrom(recordType)) 
      { 
       this.GetType().GetMethod("overrideStuff").MakeGenericMethod(recordType).Invoke(this, new object[] { model }); 
      } 
     }); 
    } 

    public void overrideStuff<T>(AutoPersistenceModel pm) where T : I 
    { 
     pm.Override<T>(a => Override(a)); 
    } 

    public abstract void Override<T>(AutoMapping<T> am) where T:I; 
} 

E un'implementazione specifica:

01.235.
public class VersionAwareAlteration : AutomappingInterfaceAlteration<IVersionAware> 
{ 
    public override void Override<T>(AutoMapping<T> am) 
    { 
     am.Map(x => x.Version).Column("VersionTest"); 
     am.ApplyFilter<VersionFilter>(); 
    } 
} 

Purtroppo ho il seguente errore ora:

[InvalidOperationException: Collection was modified; enumeration operation may not execute.] 
    System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource) +51 
    System.Collections.Generic.Enumerator.MoveNextRare() +7661017 
    System.Collections.Generic.Enumerator.MoveNext() +61 
    System.Linq.WhereListIterator`1.MoveNext() +156 
    FluentNHibernate.Utils.CollectionExtensions.Each(IEnumerable`1 enumerable, Action`1 each) +239 
    FluentNHibernate.Automapping.AutoMapper.ApplyOverrides(Type classType, IList`1 mappedProperties, ClassMappingBase mapping) +345 
    FluentNHibernate.Automapping.AutoMapper.MergeMap(Type classType, ClassMappingBase mapping, IList`1 mappedProperties) +43 
    FluentNHibernate.Automapping.AutoMapper.Map(Type classType, List`1 types) +566 
    FluentNHibernate.Automapping.AutoPersistenceModel.AddMapping(Type type) +85 
    FluentNHibernate.Automapping.AutoPersistenceModel.CompileMappings() +746 

EDIT 2: sono riuscito ad ottenere un po 'più lontano; ora invoco "Override" utilizzando la riflessione per ogni classe che implementa l'interfaccia:

public abstract class PersistenceOverride<I> 
{ 

    public void DoOverrides(AutoPersistenceModel model,IEnumerable<Type> Mytypes) 
    { 
     foreach(var t in Mytypes.Where(x=>typeof(I).IsAssignableFrom(x))) 
      ManualOverride(t,model); 
    } 

    private void ManualOverride(Type recordType,AutoPersistenceModel model) 
    { 
     var t_amt = typeof(AutoMapping<>).MakeGenericType(recordType); 
     var t_act = typeof(Action<>).MakeGenericType(t_amt); 
     var m = typeof(PersistenceOverride<I>) 
       .GetMethod("MyOverride") 
       .MakeGenericMethod(recordType) 
       .Invoke(this, null); 
     model.GetType().GetMethod("Override").MakeGenericMethod(recordType).Invoke(model, new object[] { m }); 
    } 

    public abstract Action<AutoMapping<T>> MyOverride<T>() where T:I; 
} 

public class VersionAwareOverride : PersistenceOverride<IVersionAware> 
{ 
    public override Action<AutoMapping<T>> MyOverride<T>() 
    { 
     return am => 
     { 
      am.Map(x => x.Version).Column(VersionFilter.COLUMNNAME); 
      am.ApplyFilter<VersionFilter>(); 
     }; 
    } 
} 

Tuttavia, per un motivo o un altro mio generati file HBM non contengono alcun campo "Filtro" .... Forse qualcuno potrebbe aiutarmi un po 'più lontano ora ??

risposta

1

Apparentemente, c'era un errore nella versione corrente di Nevo fluente. I filtri non sono stati copiati quando si utilizza Automapper. Override <T>.

Ho biforcuto la fonte, corretto il bug, testato, e ora ho inviato una richiesta di pull ai ragazzi fluentnhib a github.

Per ora, è possibile scaricare il codice sorgente fissato a http://github.com/ToJans/fluent-nhibernate/commit/29058de9b2bc3af85bc433aa6f71549f7b5d8e04

ora C'è anche un post completo blog su come fare questo: http://www.corebvba.be/blog/post/How-to-override-interface-mappings-and-creata-a-generic-entity-version-filter-in-fluent-nhibernate.aspx

Problemi correlati