<commit_before>﻿//-----------------------------------------------------------------------
// <copyright file="LexwareGlobalDbContext.cs" company="Fubar Development Junker">
//     Copyright (c) Fubar Development Junker. All rights reserved.
// </copyright>
// <author><NAME></author>
//-----------------------------------------------------------------------

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;

using FluentNHibernate.Cfg;

using FubarDev.Lexware.Database.NhSupport;

using JetBrains.Annotations;

using NHibernate;
using NHibernate.Cfg;
using NHibernate.Event;
using NHibernate.Linq;

using GlobalPoco = FubarDev.Lexware.Database.Global;

namespace FubarDev.Lexware.Database
{
    /// <summary>
    /// Datenbank-Kontext über den auf die Daten in der Lexware-Datenbank zugegriffen wird
    /// </summary>
    public sealed class LexwareGlobalDbContext : IDisposable
    {
        private readonly ConcurrentDictionary<SessionFactoryKey, ISessionFactory> _userSessionFactory = new ConcurrentDictionary<SessionFactoryKey, ISessionFactory>(new SessionFactoryKeyComparer());

        private readonly IStatelessSession _session;

        private NetworkCredential _superUserLogin;

        /// <summary>
        /// Initialisiert eine neue Instanz der <see cref="LexwareGlobalDbContext"/> Klasse.
        /// </summary>
        /// <param name="configurationProvider">Der für den Verbindungsaufbau zu verwendende <see cref="IConfigurationProvider"/></param>
        public LexwareGlobalDbContext(IConfigurationProvider configurationProvider)
        {
            ConfigurationProvider = configurationProvider;
            ReadOnlyLogin = new NetworkCredential("_login_", "92ab346d1c02cffc");
            ReadOnlySessionFactory = CreateSessionFactory(ReadOnlyLogin, null);
            _session = ReadOnlySessionFactory.OpenStatelessSession();
        }

        /// <summary>
        /// Holt den für den Verbindungsaufbau zu verwendenden <see cref="IConfigurationProvider"/>
        /// </summary>
        public IConfigurationProvider ConfigurationProvider { get; }

        /// <summary>
        /// Die Anmelde-Informationen für einen nur lesenden Zugriff auf die Haupt-Datenbank
        /// </summary>
        public NetworkCredential ReadOnlyLogin { get; }

        /// <summary>
        /// Die NHibernate-<see cref="ISessionFactory"/> für einen nur lesenden Zugriff auf die Haupt-Datenbank
        /// </summary>
        public ISessionFactory ReadOnlySessionFactory { get; }

        /// <summary>
        /// Holt die Anmeldeinformationen des Superusers (<code>U0</code>)
        /// </summary>
        public NetworkCredential SuperUserLogin => _superUserLogin ?? (_superUserLogin = GetSuperUserLogin());

        /// <summary>
        /// Holt eine Abfrage für die Firmen aus der globalen Datenbank
        /// </summary>
        public IQueryable<GlobalPoco.Firma> Firmen => _session.Query<GlobalPoco.Firma>();

        /// <summary>
        /// Holt eine Abfrage für die angelegten Benutzer aus der globalen Datenbank
        /// </summary>
        public IQueryable<GlobalPoco.User> Users => _session.Query<GlobalPoco.User>();

        /// <summary>
        /// Erstellt eine <see cref="ISessionFactory"/> für eine Firmendatenbank
        /// </summary>
        /// <param name="company">Die Firma für die eine <see cref="ISessionFactory"/> zur Firmendatenbank aufgebaut werden soll</param>
        /// <param name="credential">Die für den Datenbankzugriff notwendigen Anmeldeinformationen</param>
        /// <returns>Die neue <see cref="ISessionFactory"/> für den Zugriff auf die Datenbank der <paramref name="company" /></returns>
        public ISessionFactory GetCompanySessionFactory([NotNull] GlobalPoco.Firma company, [NotNull] NetworkCredential credential)
        {
            return GetSessionFactoryFor(credential, company);
        }

        /// <inheritdoc/>
        public void Dispose()
        {
            _session.Dispose();
            ReadOnlySessionFactory.Dispose();
        }

        private NetworkCredential GetSuperUserLogin()
        {
            return _session.Get<GlobalPoco.User>(0).CreateCredential();
        }

        private ISessionFactory GetSessionFactoryFor([NotNull] NetworkCredential credential, [CanBeNull] GlobalPoco.Firma company)
        {
            if (credential.UserName == ReadOnlyLogin.UserName || company == null)
                return ReadOnlySessionFactory;
            var key = new SessionFactoryKey
            {
                DbName = company.Owner,
                UserName = credential.UserName,
            };
            var result = _userSessionFactory.GetOrAdd(key, _ => CreateSessionFactory(credential, company));
            return result;
        }

        private ISessionFactory CreateSessionFactory(NetworkCredential credential, GlobalPoco.Firma company)
        {
            var cfg = CreateConfiguration(credential, company);
            var sf = cfg.BuildSessionFactory();
            return sf;
        }

        private Configuration CreateConfiguration(NetworkCredential credential, GlobalPoco.Firma company)
        {
            var cfg = ConfigurationProvider.CreateConfiguration(credential, company);
            var userName = credential.UserName == ReadOnlyLogin.UserName ? "U0" : credential.UserName;
            var listener = new AuditEntityEventListener(userName);
            cfg.SetListener(ListenerType.PreUpdate, listener);
            cfg.SetListener(ListenerType.PreInsert, listener);
            foreach (var classMapping in cfg.ClassMappings)
            {
                classMapping.AddTuplizer(EntityMode.Poco, typeof(NullableTuplizer).AssemblyQualifiedName);
            }
            var fluentConfig = Fluently.Configure(cfg)
                .Mappings(m =>
                {
                    foreach (var mappingAssembly in ConfigurationProvider.MappingAssemblies)
                        m.FluentMappings.AddFromAssembly(mappingAssembly);
                })
                .BuildConfiguration();<commit_msg>Den NullableTuplizer zu allen ClassMapping-Objekten hinzufügen<commit_after>﻿//-----------------------------------------------------------------------
// <copyright file="LexwareGlobalDbContext.cs" company="Fubar Development Junker">
//     Copyright (c) Fubar Development Junker. All rights reserved.
// </copyright>
// <author><NAME></author>
//-----------------------------------------------------------------------

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;

using FluentNHibernate.Cfg;

using FubarDev.Lexware.Database.NhSupport;

using JetBrains.Annotations;

using NHibernate;
using NHibernate.Cfg;
using NHibernate.Event;
using NHibernate.Linq;

using GlobalPoco = FubarDev.Lexware.Database.Global;

namespace FubarDev.Lexware.Database
{
    /// <summary>
    /// Datenbank-Kontext über den auf die Daten in der Lexware-Datenbank zugegriffen wird
    /// </summary>
    public sealed class LexwareGlobalDbContext : IDisposable
    {
        private readonly ConcurrentDictionary<SessionFactoryKey, ISessionFactory> _userSessionFactory = new ConcurrentDictionary<SessionFactoryKey, ISessionFactory>(new SessionFactoryKeyComparer());

        private readonly IStatelessSession _session;

        private NetworkCredential _superUserLogin;

        /// <summary>
        /// Initialisiert eine neue Instanz der <see cref="LexwareGlobalDbContext"/> Klasse.
        /// </summary>
        /// <param name="configurationProvider">Der für den Verbindungsaufbau zu verwendende <see cref="IConfigurationProvider"/></param>
        public LexwareGlobalDbContext(IConfigurationProvider configurationProvider)
        {
            ConfigurationProvider = configurationProvider;
            ReadOnlyLogin = new NetworkCredential("_login_", "92ab346d1c02cffc");
            ReadOnlySessionFactory = CreateSessionFactory(ReadOnlyLogin, null);
            _session = ReadOnlySessionFactory.OpenStatelessSession();
        }

        /// <summary>
        /// Holt den für den Verbindungsaufbau zu verwendenden <see cref="IConfigurationProvider"/>
        /// </summary>
        public IConfigurationProvider ConfigurationProvider { get; }

        /// <summary>
        /// Die Anmelde-Informationen für einen nur lesenden Zugriff auf die Haupt-Datenbank
        /// </summary>
        public NetworkCredential ReadOnlyLogin { get; }

        /// <summary>
        /// Die NHibernate-<see cref="ISessionFactory"/> für einen nur lesenden Zugriff auf die Haupt-Datenbank
        /// </summary>
        public ISessionFactory ReadOnlySessionFactory { get; }

        /// <summary>
        /// Holt die Anmeldeinformationen des Superusers (<code>U0</code>)
        /// </summary>
        public NetworkCredential SuperUserLogin => _superUserLogin ?? (_superUserLogin = GetSuperUserLogin());

        /// <summary>
        /// Holt eine Abfrage für die Firmen aus der globalen Datenbank
        /// </summary>
        public IQueryable<GlobalPoco.Firma> Firmen => _session.Query<GlobalPoco.Firma>();

        /// <summary>
        /// Holt eine Abfrage für die angelegten Benutzer aus der globalen Datenbank
        /// </summary>
        public IQueryable<GlobalPoco.User> Users => _session.Query<GlobalPoco.User>();

        /// <summary>
        /// Erstellt eine <see cref="ISessionFactory"/> für eine Firmendatenbank
        /// </summary>
        /// <param name="company">Die Firma für die eine <see cref="ISessionFactory"/> zur Firmendatenbank aufgebaut werden soll</param>
        /// <param name="credential">Die für den Datenbankzugriff notwendigen Anmeldeinformationen</param>
        /// <returns>Die neue <see cref="ISessionFactory"/> für den Zugriff auf die Datenbank der <paramref name="company" /></returns>
        public ISessionFactory GetCompanySessionFactory([NotNull] GlobalPoco.Firma company, [NotNull] NetworkCredential credential)
        {
            return GetSessionFactoryFor(credential, company);
        }

        /// <inheritdoc/>
        public void Dispose()
        {
            _session.Dispose();
            ReadOnlySessionFactory.Dispose();
        }

        private NetworkCredential GetSuperUserLogin()
        {
            return _session.Get<GlobalPoco.User>(0).CreateCredential();
        }

        private ISessionFactory GetSessionFactoryFor([NotNull] NetworkCredential credential, [CanBeNull] GlobalPoco.Firma company)
        {
            if (credential.UserName == ReadOnlyLogin.UserName || company == null)
                return ReadOnlySessionFactory;
            var key = new SessionFactoryKey
            {
                DbName = company.Owner,
                UserName = credential.UserName,
            };
            var result = _userSessionFactory.GetOrAdd(key, _ => CreateSessionFactory(credential, company));
            return result;
        }

        private ISessionFactory CreateSessionFactory(NetworkCredential credential, GlobalPoco.Firma company)
        {
            var cfg = CreateConfiguration(credential, company);
            var sf = cfg.BuildSessionFactory();
            return sf;
        }

        private Configuration CreateConfiguration(NetworkCredential credential, GlobalPoco.Firma company)
        {
            var cfg = ConfigurationProvider.CreateConfiguration(credential, company);
            var userName = credential.UserName == ReadOnlyLogin.UserName ? "U0" : credential.UserName;
            var listener = new AuditEntityEventListener(userName);
            cfg.SetListener(ListenerType.PreUpdate, listener);
            cfg.SetListener(ListenerType.PreInsert, listener);
            var fluentConfig = Fluently.Configure(cfg)
                .Mappings(m =>
                {
                    foreach (var mappingAssembly in ConfigurationProvider.MappingAssemblies)
                        m.FluentMappings.AddFromAssembly(mappingAssembly);
                })
                .BuildConfiguration();
            foreach (var classMapping in fluentConfig.ClassMappings)
            {
                classMapping.AddTuplizer(EntityMode.Poco, typeof(NullableTuplizer).AssemblyQualifiedName);
            }
{'fraction_non_alphanumeric': 0.11527213647441105, 'fraction_numerical': 0.0017871649065800163, 'mean_word_length': 2.4302033992755643, 'pattern_counts': {'":': 0, '<': 101, '<?xml version=': 0, '>': 111, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3515641', 'n_tokens_mistral': 3157, 'n_tokens_neox': 3053, 'n_words': 722}