Git Product home page Git Product logo

coreddd's People

Contributors

buthrakaur avatar gitter-badger avatar kamalpatel125 avatar xhafan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

coreddd's Issues

NhibernateUnitOfWork is not gracefully disposed when begin transaction throws

Got this random exception when starting a transaction in NhibernateUnitOfWork.BeginTransaction , line Session.BeginTransaction(isolationLevel):

NHibernate.TransactionException: Begin failed with SQL exception
 ---> Npgsql.NpgsqlException (0x80004005): Exception while reading from stream
 ---> System.TimeoutException: Timeout during reading attempt
   at Npgsql.Internal.NpgsqlReadBuffer.<Ensure>g__EnsureLong|41_0(NpgsqlReadBuffer buffer, Int32 count, Boolean async, Boolean readingNotifications)
   at Npgsql.Internal.NpgsqlConnector.RawOpen(SslMode sslMode, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken, Boolean isFirstAttempt)
   at Npgsql.Internal.NpgsqlConnector.<Open>g__OpenCore|191_1(NpgsqlConnector conn, SslMode sslMode, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken, Boolean isFirstAttempt)
   at Npgsql.Internal.NpgsqlConnector.Open(NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
   at Npgsql.ConnectorPool.OpenNewConnector(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
   at Npgsql.ConnectorPool.<Get>g__RentAsync|28_0(NpgsqlConnection conn, NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
   at Npgsql.NpgsqlConnection.<Open>g__OpenAsync|45_0(Boolean async, CancellationToken cancellationToken)
   at Npgsql.NpgsqlConnection.Open()
   at NHibernate.Connection.DriverConnectionProvider.GetConnection(String connectionString)
   at NHibernate.AdoNet.ConnectionManager.GetConnection()
   at NHibernate.Transaction.AdoTransaction.Begin(IsolationLevel isolationLevel)
   --- End of inner exception stack trace ---
   at NHibernate.Transaction.AdoTransaction.Begin(IsolationLevel isolationLevel)
   at NHibernate.Impl.AbstractSessionImpl.BeginTransaction(IsolationLevel isolationLevel)
   at CoreDdd.Nhibernate.UnitOfWorks.NhibernateUnitOfWork.BeginTransaction(IsolationLevel isolationLevel)
   at CoreDdd.AspNetCore.Middlewares.BaseUnitOfWorkMiddleware.InvokeAsync(HttpContext context, RequestDelegate next, IUnitOfWork unitOfWork)

And when disposing the NhibernateUnitOfWork instance, got another exception:

NHibernate.TransactionException: Transaction not successfully started
   at NHibernate.Transaction.AdoTransaction.CheckBegun()
   at NHibernate.Transaction.AdoTransaction.Commit()
   at CoreDdd.Nhibernate.UnitOfWorks.NhibernateUnitOfWork.Commit()
   at CoreDdd.Nhibernate.UnitOfWorks.NhibernateUnitOfWork.Dispose()
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.DisposeAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Http.Features.RequestServicesFeature.<DisposeAsync>g__Awaited|9_0(RequestServicesFeature servicesFeature, ValueTask vt)
   at Microsoft.AspNetCore.Server.Kestrel.Core

The second exception is avoidable by an improved detection that the transaction has not been started on the NhibernateUnitOfWork instance.

Add support for session-scoped interceptors

Currently only session-factory-scoped interceptors are supported via overriding BaseNhibernateConfigurator.AdditionalConfiguration:

    protected override void AdditionalConfiguration(Configuration configuration)
    {
        configuration.SetInterceptor(new SomeInterceptor());
    }

Quick idea for the support for session-scoped intereceptors:

public NhibernateUnitOfWork(INhibernateConfigurator configurator, IInterceptor interceptor = null)
{
    _configurator = configurator;
    _interceptor = interceptor;
}
...
        public void BeginTransaction(System.Data.IsolationLevel isolationLevel = System.Data.IsolationLevel.Unspecified)
        {
            _isInTransactionScope = Transaction.Current != null;

            var sessionFactory = _configurator.GetSessionFactory();
            
#if !NET40 && !NET45
            if (_interceptor != null)
            {
                sessionFactory.WithOptions().Interceptor(_interceptor);
            }
            Session = sessionFactory.OpenSession();
#else
            Session = _interceptor != null 
                ? sessionFactory.OpenSession(_interceptor) 
                : sessionFactory.OpenSession();
#endif
            if (_isInTransactionScope) return;

            Session.BeginTransaction(isolationLevel);
        }

Maybe support collection of intereceptors, and use the following CompositeInterceptor:

using System.Collections;
using System.Collections.Generic;
using NHibernate;
using NHibernate.SqlCommand;
using NHibernate.Type;

// taken from https://stackoverflow.com/a/33289268/379279 and modified for nullable 
public class CompositeInterceptor(IEnumerable<IInterceptor> interceptors) : IInterceptor
{
    private readonly IEnumerable<IInterceptor> _interceptors = interceptors.ToList();

    public void AfterTransactionBegin(ITransaction tx)
    {
        foreach (var interceptor in _interceptors)
        {
            interceptor.AfterTransactionBegin(tx);
        }
    }

    public void AfterTransactionCompletion(ITransaction tx)
    {
        foreach (var interceptor in _interceptors)
        {
            interceptor.AfterTransactionCompletion(tx);
        }
    }

    public void BeforeTransactionCompletion(ITransaction tx)
    {
        foreach (var interceptor in _interceptors)
        {
            interceptor.BeforeTransactionCompletion(tx);
        }
    }

    public int[]? FindDirty(
        object entity, 
        object id, 
        object[] currentState, 
        object[] previousState, 
        string[] propertyNames, 
        IType[] types
    )
    {
        var results = _interceptors
            .Select(interceptor => interceptor.FindDirty(entity, id, currentState, previousState, propertyNames, types))
            .Where(result => result != null)
            .SelectMany(x => x)
            .Distinct()
            .ToArray();
        return !results.Any() ? null : results;
    }

    public object? GetEntity(string entityName, object id)
    {
        return _interceptors
            .Select(interceptor => interceptor.GetEntity(entityName, id))
            .FirstOrDefault(result => result != null);
    }

    public string? GetEntityName(object entity)
    {
        return _interceptors
            .Select(interceptor => interceptor.GetEntityName(entity))
            .FirstOrDefault(result => result != null);
    }

    public object? Instantiate(string entityName, object id)
    {
        return _interceptors
            .Select(interceptor => interceptor.Instantiate(entityName, id))
            .FirstOrDefault(result => result != null);
    }

    public bool? IsTransient(object entity)
    {
        return _interceptors
            .Select(interceptor => interceptor.IsTransient(entity))
            .FirstOrDefault(result => result != null);
    }

    public void OnCollectionRecreate(object collection, object key)
    {
        foreach (var interceptor in _interceptors)
        {
            interceptor.OnCollectionRecreate(collection, key);
        }
    }

    public void OnCollectionRemove(object collection, object key)
    {
        foreach (var interceptor in _interceptors)
        {
            interceptor.OnCollectionRemove(collection, key);
        }
    }

    public void OnCollectionUpdate(object collection, object key)
    {
        foreach (var interceptor in _interceptors)
        {
            interceptor.OnCollectionUpdate(collection, key);
        }
    }

    public void OnDelete(
        object entity, 
        object id, 
        object[] state, 
        string[] propertyNames, 
        IType[] types
    )
    {
        foreach (var interceptor in _interceptors)
        {
            interceptor.OnDelete(entity, id, state, propertyNames, types);
        }
    }

    public bool OnFlushDirty(
        object entity, 
        object id, 
        object[] currentState, 
        object[] previousState, 
        string[] propertyNames, 
        IType[] types
    )
    {
        return _interceptors.Any(interceptor => interceptor.OnFlushDirty(entity, id, currentState, previousState, propertyNames, types));
    }

    public bool OnLoad(
        object entity, 
        object id, 
        object[] state, 
        string[] propertyNames,
        IType[] types
    )
    {
        return _interceptors.Any(interceptor => interceptor.OnLoad(entity, id, state, propertyNames, types));
    }

    public SqlString OnPrepareStatement(SqlString sql)
    {
        return _interceptors.Aggregate(sql, (current, interceptor) => interceptor.OnPrepareStatement(current));
    }

    public bool OnSave(
        object entity, 
        object id, 
        object[] state, 
        string[] propertyNames, 
        IType[] types
    )
    {
        return _interceptors.Any(interceptor => interceptor.OnSave(entity, id, state, propertyNames, types));
    }

    public void PostFlush(ICollection entities)
    {
        foreach (var interceptor in _interceptors)
        {
            interceptor.PostFlush(entities);
        }
    }

    public void PreFlush(ICollection entities)
    {
        foreach (var interceptor in _interceptors)
        {
            interceptor.PreFlush(entities);
        }
    }

    public void SetSession(ISession session)
    {
        foreach (var interceptor in _interceptors)
        {
            interceptor.SetSession(session);
        }
    }
}

More info about interceptors:

Improvement - NHibernate configuration - Add attributes to mark classes for NHibernate mapping

Currently one needs to override methods in NhibernateConfigurator to customize NHibernate mapping.

Examples:

  • to map a class as NHibernate component, one needs to override BaseNhibernateConfigurator.GetComponentTypes() (code sample here)
  • to map a class hierarchy as a discriminated type saving the whole class hierarchy into one table, one needs to override BaseNhibernateConfigurator.GetDiscriminatedTypes() (code sample here)

The same goes for other methods in BaseNhibernateConfigurator (GetIncludeBaseTypes, GetIgnoreBaseTypes).

It would be handy to have a set of attributes to mark a class as NHibernate component, or mark it as a discriminated type, or mark a base class as "included" in mapping or "ignored" from mapping.

Hot Reload seems not to work properly for ASP.NET Core

Error:

2022-04-26 13:06:35.722 +02:00 [ERR] An unhandled exception has occurred while executing the request.
System.InvalidCastException: Unable to cast object of type '<some entity>' to type 'NHibernate.Proxy.INHibernateProxy'.
   at PointOfInterestProxy.NHibernate.Proxy.INHibernateProxy.get_HibernateLazyInitializer()
   at NHibernate.Engine.StatefulPersistenceContext.Clear()
   at NHibernate.Impl.SessionImpl.Close()
   at NHibernate.Impl.SessionImpl.Dispose(Boolean isDisposing)
   at NHibernate.Impl.SessionImpl.Dispose()
   at CoreDdd.Nhibernate.UnitOfWorks.NhibernateUnitOfWork.RollbackAsync()
   at CoreDdd.AspNetCore.Middlewares.BaseUnitOfWorkMiddleware.InvokeAsync(HttpContext context, RequestDelegate next, IUnitOfWork unitOfWork)
   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

How to replicate: Hot Reload a change, execute the change couple of times.

Do not map dtos into the database automatically

Change BaseNhibernateConfigurator default implementation

protected virtual Func<Type, bool> GetIsTypeDtoFunc()
        {
            return type => type.Name.EndsWith("Dto");
        }

not to map dtos into the database automatically.

Cannot map IDictionary AsMap

HasManyConvention automapping supports only lists and sets, and not maps. IDictionary collection is incorrectly marked AsSet.

Support NHibernate component automapping

Currently NHibernate components needs to be mapped manually (e.g. entity.Component(x => x.SomeComponent); Make sure component classes can be easily identified as NHibernate components to avoid the manual mapping. Also make sure these kind of additional NHibernate configurations can be added without the CoreDdd libs code change.

Enable TreatWarningsAsErrors

Add to CommonNugetAssemblyInfo.props:

<WarningsAsErrors>NU1605;CS4014</WarningsAsErrors>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.