


Erweitern von Ardalis.Specification für NHibernate mit Linq, Criteria API und Query Over
Ardalis.Specification ist eine leistungsstarke Bibliothek, die das Spezifikationsmuster zum Abfragen von Datenbanken ermöglicht. Sie wurde hauptsächlich für Entity Framework Core entwickelt. Hier zeige ich jedoch, wie Sie Ardalis.Specification für die Verwendung erweitern können NHibernate auch als ORM.
In diesem Blogbeitrag wird davon ausgegangen, dass Sie über Erfahrung mit Ardalis.Specification verfügen und es in einem Projekt mit NHibernate verwenden möchten. Wenn Sie mit Ardalis.Specification noch nicht vertraut sind, lesen Sie die Dokumentation, um mehr zu erfahren.
Erstens gibt es in NHibernate drei verschiedene integrierte Möglichkeiten, Abfragen durchzuführen
- Linq zur Abfrage (mit IQueryable)
- Kriterien-API
- Abfrage beendet
Ich werde durchgehen, wie Sie Ardalis.Specification erweitern können, um alle drei Möglichkeiten zu verarbeiten, aber da Linq to Query auch mit IQueryable wie Entity Framework Core funktioniert, werde ich zuerst diese Option durchgehen.
Linq zur Abfrage
Es gibt eine kleine Nuance zwischen Entity Framework Core und NHIbernate, wenn es um die Erstellung von Join-Beziehungen geht. In Entity Framework Core haben wir Erweiterungsmethoden für IQueryable: Include und ThenInclude (dies sind auch die Methodennamen, die in Ardalis.Specification verwendet werden).
Fetch, FetchMany, ThenFetch und ThenFetchMany sind NHibernate-spezifische Methoden auf IQueryable, die Verknüpfungen durchführen. Der IEvaluator bietet uns die Erweiterbarkeit, die wir benötigen, um die richtige Erweiterungsmethode aufzurufen, wenn wir mit NHibernate arbeiten.
Fügen Sie eine Implementierung von IEvaluator wie folgt hinzu:
public class FetchEvaluator : IEvaluator { private static readonly MethodInfo FetchMethodInfo = typeof(EagerFetchingExtensionMethods) .GetTypeInfo().GetDeclaredMethods(nameof(EagerFetchingExtensionMethods.Fetch)) .Single(); private static readonly MethodInfo FetchManyMethodInfo = typeof(EagerFetchingExtensionMethods) .GetTypeInfo().GetDeclaredMethods(nameof(EagerFetchingExtensionMethods.FetchMany)) .Single(); private static readonly MethodInfo ThenFetchMethodInfo = typeof(EagerFetchingExtensionMethods) .GetTypeInfo().GetDeclaredMethods(nameof(EagerFetchingExtensionMethods.ThenFetch)) .Single(); private static readonly MethodInfo ThenFetchManyMethodInfo = typeof(EagerFetchingExtensionMethods) .GetTypeInfo().GetDeclaredMethods(nameof(EagerFetchingExtensionMethods.ThenFetchMany)) .Single(); public static FetchEvaluator Instance { get; } = new FetchEvaluator(); public IQueryable<t> GetQuery<t>(IQueryable<t> query, ISpecification<t> specification) where T : class { foreach (var includeInfo in specification.IncludeExpressions) { query = includeInfo.Type switch { IncludeTypeEnum.Include => BuildInclude<t>(query, includeInfo), IncludeTypeEnum.ThenInclude => BuildThenInclude<t>(query, includeInfo), _ => query }; } return query; } public bool IsCriteriaEvaluator { get; } = false; private IQueryable<t> BuildInclude<t>(IQueryable query, IncludeExpressionInfo includeInfo) { _ = includeInfo ?? throw new ArgumentNullException(nameof(includeInfo)); var methodInfo = (IsGenericEnumerable(includeInfo.PropertyType, out var propertyType) ? FetchManyMethodInfo : FetchMethodInfo); var method = methodInfo.MakeGenericMethod(includeInfo.EntityType, propertyType); var result = method.Invoke(null, new object[] { query, includeInfo.LambdaExpression }); _ = result ?? throw new TargetException(); return (IQueryable<t>)result; } private IQueryable<t> BuildThenInclude<t>(IQueryable query, IncludeExpressionInfo includeInfo) { _ = includeInfo ?? throw new ArgumentNullException(nameof(includeInfo)); _ = includeInfo.PreviousPropertyType ?? throw new ArgumentNullException(nameof(includeInfo.PreviousPropertyType)); var method = (IsGenericEnumerable(includeInfo.PreviousPropertyType, out var previousPropertyType) ? ThenFetchManyMethodInfo : ThenFetchMethodInfo); IsGenericEnumerable(includeInfo.PropertyType, out var propertyType); var result = method.MakeGenericMethod(includeInfo.EntityType, previousPropertyType, propertyType) .Invoke(null, new object[] { query, includeInfo.LambdaExpression }); _ = result ?? throw new TargetException(); return (IQueryable<t>)result; } private static bool IsGenericEnumerable(Type type, out Type propertyType) { if (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(IEnumerable))) { propertyType = type.GenericTypeArguments[0]; return true; } propertyType = type; return false; } } </t></t></t></t></t></t></t></t></t></t></t></t>
Als nächstes müssen wir ISpecificationEvaluator für die Verwendung unseres FetchEvaluator (und anderer Evaluatoren) konfigurieren. Wir fügen wie folgt eine Implementierung ISpecificationEvaluator hinzu, wobei die Evaluatoren im Konstruktor konfiguriert sind. WhereEvaluator, OrderEvaluator und PaginationEvaluator sind alle in der Ardalis.Specification enthalten und funktionieren auch gut mit NHibernate.
public class LinqToQuerySpecificationEvaluator : ISpecificationEvaluator { private List<ievaluator> Evaluators { get; } = new List<ievaluator>(); public LinqToQuerySpecificationEvaluator() { Evaluators.AddRange(new IEvaluator[] { WhereEvaluator.Instance, OrderEvaluator.Instance, PaginationEvaluator.Instance, FetchEvaluator.Instance }); } public IQueryable<tresult> GetQuery<t tresult>(IQueryable<t> query, ISpecification<t tresult> specification) where T : class { if (specification is null) throw new ArgumentNullException(nameof(specification)); if (specification.Selector is null && specification.SelectorMany is null) throw new SelectorNotFoundException(); if (specification.Selector is not null && specification.SelectorMany is not null) throw new ConcurrentSelectorsException(); query = GetQuery(query, (ISpecification<t>)specification); return specification.Selector is not null ? query.Select(specification.Selector) : query.SelectMany(specification.SelectorMany!); } public IQueryable<t> GetQuery<t>(IQueryable<t> query, ISpecification<t> specification, bool evaluateCriteriaOnly = false) where T : class { if (specification is null) throw new ArgumentNullException(nameof(specification)); var evaluators = evaluateCriteriaOnly ? Evaluators.Where(x => x.IsCriteriaEvaluator) : Evaluators; foreach (var evaluator in evaluators) query = evaluator.GetQuery(query, specification); return query; } } </t></t></t></t></t></t></t></t></tresult></ievaluator></ievaluator>
Jetzt können wir in unserem Repository einen Verweis auf LinqToQuerySpecificationEvaluator erstellen, der etwa so aussehen könnte:
public class Repository : IRepository { private readonly ISession _session; private readonly ISpecificationEvaluator _specificationEvaluator; public Repository(ISession session) { _session = session; _specificationEvaluator = new LinqToQuerySpecificationEvaluator(); } ... other repository methods public IEnumerable<t> List<t>(ISpecification<t> specification) where T : class { return _specificationEvaluator.GetQuery(_session.Query<t>().AsQueryable(), specification).ToList(); } public IEnumerable<tresult> List<t tresult>(ISpecification<t tresult> specification) where T : class { return _specificationEvaluator.GetQuery(_session.Query<t>().AsQueryable(), specification).ToList(); } public void Dispose() { _session.Dispose(); } } </t></t></t></tresult></t></t></t></t>
Das ist es. Wir können jetzt Linq to Query in unseren Spezifikationen verwenden, genau wie wir es normalerweise mit Ardalis tun.Specification:
public class TrackByName : Specification<core.entitites.track> { public TrackByName(string trackName) { Query.Where(x => x.Name == trackName); } } </core.entitites.track>
Nachdem wir uns nun mit Linq-basierten Abfragen befasst haben, gehen wir zum Umgang mit Criteria API und Query Over über, die einen anderen Ansatz erfordern.
Mischen von Linq, Criteria und Query Over in NHibernate
Da Criteria API und Query Over über eine eigene Implementierung zum Generieren von SQL verfügen und nicht IQueryable verwenden, sind sie nicht mit der IEvaluator-Schnittstelle kompatibel. Meine Lösung besteht darin, in diesem Fall die Verwendung der IEvaluator-Schnittstelle für diese Methoden zu vermeiden und mich stattdessen auf die Vorteile des Spezifikationsmusters zu konzentrieren. Aber ich möchte auch mischen können
Linq to Query, Criteria und Query Over in meiner Lösung (wenn Sie nur eine dieser Implementierungen benötigen, können Sie sich für Ihre besten Anforderungen entscheiden).
Dazu füge ich vier neue Klassen hinzu, die Specification oder Specification erben
HINWEIS: Die Assembly, in der Sie diese Klassen definieren, benötigt einen Verweis auf NHibernate, da wir Aktionen für Kriterien und ein QueryOver definieren, das in NHibernate zu finden ist
public class CriteriaSpecification<t> : Specification<t> { private Action<icriteria>? _action; public Action<icriteria> GetCriteria() => _action ?? throw new NotSupportedException("The criteria has not been specified. Please use UseCriteria() to define the criteria."); protected void UseCriteria(Action<icriteria> action) => _action = action; } public class CriteriaSpecification<t tresult> : Specification<t tresult> { private Action<icriteria>? _action; public Action<icriteria> GetCriteria() => _action ?? throw new NotSupportedException("The criteria has not been specified. Please use UseCriteria() to define the criteria."); protected void UseCriteria(Action<icriteria> action) => _action = action; } public class QueryOverSpecification<t> : Specification<t> { private Action<iqueryover t>>? _action; public Action<iqueryover t>> GetQueryOver() => _action ?? throw new NotSupportedException("The Query over has not been specified. Please use the UseQueryOver() to define the query over."); protected void UseQueryOver(Action<iqueryover t>> action) => _action = action; } public class QueryOverSpecification<t tresult> : Specification<t tresult> { private Func<iqueryover t>, IQueryOver<t t>>? _action; public Func<iqueryover t>, IQueryOver<t t>> GetQueryOver() => _action ?? throw new NotSupportedException("The Query over has not been specified. Please use the UseQueryOver() to define the query over."); protected void UseQueryOver(Func<iqueryover t>, IQueryOver<t t>> action) => _action = action; } </t></iqueryover></t></iqueryover></t></iqueryover></t></t></iqueryover></iqueryover></iqueryover></t></t></icriteria></icriteria></icriteria></t></t></icriteria></icriteria></icriteria></t></t>
Dann können wir den Mustervergleich in unserem Repository verwenden, um die Art und Weise zu ändern, wie wir Abfragen mit NHibernate durchführen
public IEnumerable<t> List<t>(ISpecification<t> specification) where T : class { return specification switch { CriteriaSpecification<t> criteriaSpecification => _session.CreateCriteria<t>() .Apply(query => criteriaSpecification.GetCriteria().Invoke(query)) .List<t>(), QueryOverSpecification<t> queryOverSpecification => _session.QueryOver<t>() .Apply(queryOver => queryOverSpecification.GetQueryOver().Invoke(queryOver)) .List<t>(), _ => _specificationEvaluator.GetQuery(_session.Query<t>().AsQueryable(), specification).ToList() }; } public IEnumerable<tresult> List<t tresult>(ISpecification<t tresult> specification) where T : class { return specification switch { CriteriaSpecification<t tresult> criteriaSpecification => _session.CreateCriteria<t>() .Apply(query => criteriaSpecification.GetCriteria().Invoke(query)) .List<tresult>(), QueryOverSpecification<t tresult> queryOverSpecification => _session.QueryOver<t>() .Apply(queryOver => queryOverSpecification.GetQueryOver().Invoke(queryOver)) .List<tresult>(), _ => _specificationEvaluator.GetQuery(_session.Query<t>().AsQueryable(), specification).ToList() }; } </t></tresult></t></t></tresult></t></t></t></t></tresult></t></t></t></t></t></t></t></t></t></t>
Die obige Apply()-Methode ist eine Erweiterungsmethode, die die Abfrage auf eine einzelne Zeile vereinfacht:
public static class QueryExtensions { public static T Apply<t>(this T obj, Action<t> action) { action(obj); return obj; } public static TResult Apply<t tresult>(this T obj, Func<t tresult> func) { return func(obj); } } </t></t></t></t>
Beispiel für eine Kriterienspezifikation
HINWEIS: Die Assembly, in der Sie diese Klassen definieren, benötigt einen Verweis auf NHibernate, da wir Aktionen für Kriterien definieren, die in NHibernate zu finden sind
public class TrackByNameCriteria : CriteriaSpecification<track> { public TrackByNameCriteria(string trackName) { this.UseCriteria(criteria => criteria.Add(Restrictions.Eq(nameof(Track.Name), trackName))); } } </track>
Beispiel für eine Abfrage nach einer Spezifikation
HINWEIS: Die Assembly, in der Sie diese Klassen definieren, benötigt einen Verweis auf NHibernate, da wir Aktionen für ein QueryOver definieren, das in NHibernate zu finden ist
public class TrackByNameQueryOver : QueryOverSpecification<track> { public TrackByNameQueryOver(string trackName) { this.UseQueryOver(queryOver => queryOver.Where(x => x.Name == trackName)); } } </track>
Durch die Erweiterung von Ardalis.Specification für NHibernate erschließen wir die Möglichkeit, Linq to Query, Criteria API und Query Over zu verwenden – alles innerhalb eines einzigen Repository-Musters. Dieser Ansatz bietet eine äußerst anpassungsfähige und leistungsstarke Lösung für NHibernate-Benutzer
Das obige ist der detaillierte Inhalt vonErweitern von Ardalis.Specification für NHibernate mit Linq, Criteria API und Query Over. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Es gibt signifikante Unterschiede in den Lernkurven von C# und C- und Entwicklererfahrung. 1) Die Lernkurve von C# ist relativ flach und für rasche Entwicklung und Anwendungen auf Unternehmensebene geeignet. 2) Die Lernkurve von C ist steil und für Steuerszenarien mit hoher Leistung und niedrigem Level geeignet.

Es gibt signifikante Unterschiede in der Implementierung von C# und C in der objektorientierten Programmierung (OOP). 1) Die Klassendefinition und die Syntax von C# sind prägnanter und unterstützen erweiterte Funktionen wie Linq. 2) C bietet eine feinere granulare Kontrolle, die für die Systemprogrammierung und den hohen Leistungsbedarf geeignet ist. Beide haben ihre eigenen Vorteile, und die Wahl sollte auf dem spezifischen Anwendungsszenario basieren.

Das Konvertieren von XML in C und die Durchführung von Datenvorgängen kann in den folgenden Schritten erreicht werden: 1) Parsing XML -Dateien mithilfe der TinyXML2 -Bibliothek, 2) Daten in die Datenstruktur von C mithilfe der C -Standardbibliothek wie STD :: Vector für Datenoperationen in C -Datenstruktur zuzuordnen. Durch diese Schritte können Daten aus XML konvertiert und effizient bearbeitet werden.

C# verwendet den automatischen Müllsammlungsmechanismus, während C die manuelle Speicherverwaltung verwendet. Der Müllkollektor von 1. C#verwaltet automatisch den Speicher, um das Risiko eines Speicherlecks zu verringern, kann jedoch zu einer Leistungsverschlechterung führen. 2.C bietet eine flexible Speicherregelung, die für Anwendungen geeignet ist, die eine feine Verwaltung erfordern, aber mit Vorsicht behandelt werden sollten, um Speicherleckage zu vermeiden.

C hat immer noch wichtige Relevanz für die moderne Programmierung. 1) Hochleistungs- und direkte Hardware-Betriebsfunktionen machen es zur ersten Wahl in den Bereichen Spieleentwicklung, eingebettete Systeme und Hochleistungs-Computing. 2) Reiche Programmierparadigmen und moderne Funktionen wie Smart -Zeiger und Vorlagenprogrammierung verbessern seine Flexibilität und Effizienz. Obwohl die Lernkurve steil ist, machen sie im heutigen Programmierökosystem immer noch wichtig.

C -Lernende und Entwickler können Ressourcen und Unterstützung von Stackoverflow, Reddits R/CPP -Community, Coursera und EDX -Kursen, Open -Source -Projekten zu Github, professionellen Beratungsdiensten und CPPCON erhalten. 1. Stackoverflow gibt Antworten auf technische Fragen. 2. Die R/CPP -Community von Reddit teilt die neuesten Nachrichten; 3.. Coursera und EDX bieten formelle C -Kurse; 4. Open Source -Projekte auf Github wie LLVM und Boost verbessern die Fähigkeiten; 5. Professionelle Beratungsdienste wie Jetbrains und Perforce bieten technische Unterstützung; 6. CPPCON und andere Konferenzen helfen Karrieren

C# eignet sich für Projekte, die eine hohe Entwicklungseffizienz und plattformübergreifende Unterstützung erfordern, während C für Anwendungen geeignet ist, die eine hohe Leistung und die zugrunde liegende Kontrolle erfordern. 1) C# vereinfacht die Entwicklung, bietet Müllsammlung und reichhaltige Klassenbibliotheken, die für Anwendungen auf Unternehmensebene geeignet sind. 2) C ermöglicht den direkten Speicherbetrieb, der für Spielentwicklung und Hochleistungs-Computing geeignet ist.

C Gründe für die kontinuierliche Verwendung sind seine hohe Leistung, breite Anwendung und sich weiterentwickelnde Eigenschaften. 1) Leistung mit hoher Effizienz. 2) weit verbreitete: Glanz in den Feldern der Spieleentwicklung, eingebettete Systeme usw. 3) Kontinuierliche Entwicklung: Seit seiner Veröffentlichung im Jahr 1983 hat C weiterhin neue Funktionen hinzugefügt, um seine Wettbewerbsfähigkeit aufrechtzuerhalten.


Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

AI Hentai Generator
Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

Heiße Werkzeuge

WebStorm-Mac-Version
Nützliche JavaScript-Entwicklungstools

Dreamweaver CS6
Visuelle Webentwicklungstools

Herunterladen der Mac-Version des Atom-Editors
Der beliebteste Open-Source-Editor

DVWA
Damn Vulnerable Web App (DVWA) ist eine PHP/MySQL-Webanwendung, die sehr anfällig ist. Seine Hauptziele bestehen darin, Sicherheitsexperten dabei zu helfen, ihre Fähigkeiten und Tools in einem rechtlichen Umfeld zu testen, Webentwicklern dabei zu helfen, den Prozess der Sicherung von Webanwendungen besser zu verstehen, und Lehrern/Schülern dabei zu helfen, in einer Unterrichtsumgebung Webanwendungen zu lehren/lernen Sicherheit. Das Ziel von DVWA besteht darin, einige der häufigsten Web-Schwachstellen über eine einfache und unkomplizierte Benutzeroberfläche mit unterschiedlichen Schwierigkeitsgraden zu üben. Bitte beachten Sie, dass diese Software

Sicherer Prüfungsbrowser
Safe Exam Browser ist eine sichere Browserumgebung für die sichere Teilnahme an Online-Prüfungen. Diese Software verwandelt jeden Computer in einen sicheren Arbeitsplatz. Es kontrolliert den Zugriff auf alle Dienstprogramme und verhindert, dass Schüler nicht autorisierte Ressourcen nutzen.