2010-04-13 4 views
5

In meiner Suche nach einer Version weiter Datenbank-Filter für eine Anwendung zur Verfügung zu stellen, habe ich den folgenden Code geschrieben habe:Was ist der beste Weg, um eine AutoMappingOverride für eine Schnittstelle in FluentNHibernate AutoMapper

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 
    } 

} 

Aber da Überschreibungen arbeite nicht an Schnittstellen, ich suche nach einer Möglichkeit, dies zu implementieren. Derzeit verwende ich diese (eher umständlich) Art und Weise für jede Klasse, die die Schnittstelle implementiert:

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 
} 

Ich habe usw. an IClassmap Schnittstellen gesucht, aber sie scheinen nicht einen Weg, um die ApplyFilter Methode für den Zugriff auf , also habe ich hier keine Ahnung ...

Da ich wahrscheinlich nicht der erste bin, der dieses Problem hat, bin ich mir ziemlich sicher, dass es möglich sein sollte; Ich bin nur nicht ganz sicher, wie das funktioniert ..

EDIT: Ich habe ein bisschen näher an eine generische Lösung bekommen:

Dies ist die Art und Weise habe ich versucht, es zu lösen:

Verwendung eine generische Klasse, Änderungen an Klassen zu implementieren, um eine Schnittstelle implementiert:

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

und eine spezifische Implementierung:

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

Leider bekomme ich folgende Fehlermeldung jetzt:

[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: Ich ein bisschen weiter erhalten verwaltet werden; ich jetzt für jede Klasse „überschreiben“ mit Reflexion aufrufen, die die Schnittstelle implementiert:

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

jedoch für einen oder anderen Grund meiner erzeugt hbm Dateien haben keine „Filter“ Felder nicht enthalten .... Vielleicht jemand Könnte mir das jetzt ein bisschen weiterhelfen ??

Antwort

1

Offenbar gab es einen Fehler in der aktuellen Version von Fluent-Nhibernate. Die Filter wurden nicht kopiert, wenn Sie Automapper.Override <T> verwenden.

Ich verzweigte die Quelle, reparierte den Fehler, getestet, und ich habe jetzt eine Pull-Anfrage an die fluentnhib Jungs über bei Github gesendet.

Vorerst können Sie den festen Quelltext bei http://github.com/ToJans/fluent-nhibernate/commit/29058de9b2bc3af85bc433aa6f71549f7b5d8e04

Download ist jetzt gibt auch eine komplette Blog-Post auf, wie dies zu tun: http://www.corebvba.be/blog/post/How-to-override-interface-mappings-and-creata-a-generic-entity-version-filter-in-fluent-nhibernate.aspx

Verwandte Themen