diff --git a/src/Paillave.EntityFrameworkCoreExtension/Paillave.EntityFrameworkCoreExtension.csproj b/src/Paillave.EntityFrameworkCoreExtension/Paillave.EntityFrameworkCoreExtension.csproj index 33fe890d..2fbff7ae 100644 --- a/src/Paillave.EntityFrameworkCoreExtension/Paillave.EntityFrameworkCoreExtension.csproj +++ b/src/Paillave.EntityFrameworkCoreExtension/Paillave.EntityFrameworkCoreExtension.csproj @@ -1,7 +1,7 @@ Paillave.EntityFrameworkCoreExtension - 2.1.5-beta + 2.1.6-beta Stéphane Royer true diff --git a/src/Paillave.Etl.Autofac/AutofacDependencyResolver.cs b/src/Paillave.Etl.Autofac/AutofacDependencyResolver.cs index d44d059e..12e92681 100644 --- a/src/Paillave.Etl.Autofac/AutofacDependencyResolver.cs +++ b/src/Paillave.Etl.Autofac/AutofacDependencyResolver.cs @@ -50,5 +50,20 @@ public bool TryResolve(Type type, out object resolved) { return _componentContext.TryResolve(type, out resolved); } + + public object Resolve(Type type, string key) + { + var res = _dependencyResolver.Resolve(type, key); + if (res != null) return res; + res = _componentContext.ResolveKeyed(key, type); + _dependencyResolver.Register(type, res, key); + return res; + } + + public bool TryResolve(Type type, string key, out object resolved) + { + resolved = default; + return _componentContext.TryResolveKeyed(key, type, out resolved); + } } } \ No newline at end of file diff --git a/src/Paillave.Etl.Autofac/Paillave.Etl.Autofac.csproj b/src/Paillave.Etl.Autofac/Paillave.Etl.Autofac.csproj index ae2ecaa6..c767fa7e 100644 --- a/src/Paillave.Etl.Autofac/Paillave.Etl.Autofac.csproj +++ b/src/Paillave.Etl.Autofac/Paillave.Etl.Autofac.csproj @@ -1,7 +1,7 @@ Paillave.EtlNet.Autofac - 2.1.5-beta + 2.1.6-beta Stéphane Royer true diff --git a/src/Paillave.Etl.Bloomberg/Paillave.Etl.Bloomberg.csproj b/src/Paillave.Etl.Bloomberg/Paillave.Etl.Bloomberg.csproj index c926aa3d..9537568f 100644 --- a/src/Paillave.Etl.Bloomberg/Paillave.Etl.Bloomberg.csproj +++ b/src/Paillave.Etl.Bloomberg/Paillave.Etl.Bloomberg.csproj @@ -1,7 +1,7 @@ Paillave.EtlNet.Bloomberg - 2.1.5-beta + 2.1.6-beta Stéphane Royer true diff --git a/src/Paillave.Etl.Dropbox/Paillave.Etl.Dropbox.csproj b/src/Paillave.Etl.Dropbox/Paillave.Etl.Dropbox.csproj index 6e4a629e..21481536 100644 --- a/src/Paillave.Etl.Dropbox/Paillave.Etl.Dropbox.csproj +++ b/src/Paillave.Etl.Dropbox/Paillave.Etl.Dropbox.csproj @@ -1,7 +1,7 @@ Paillave.EtlNet.Dropbox - 2.1.5-beta + 2.1.6-beta Stéphane Royer true diff --git a/src/Paillave.Etl.EntityFrameworkCore/EfCoreSaveStreamNode.cs b/src/Paillave.Etl.EntityFrameworkCore/EfCoreSaveStreamNode.cs index 20a09f3d..0b11b4ca 100644 --- a/src/Paillave.Etl.EntityFrameworkCore/EfCoreSaveStreamNode.cs +++ b/src/Paillave.Etl.EntityFrameworkCore/EfCoreSaveStreamNode.cs @@ -7,86 +7,93 @@ using System.Linq.Expressions; using Paillave.EntityFrameworkCoreExtension.EfSave; using Paillave.EntityFrameworkCoreExtension.BulkSave; +using System.Threading.Tasks; -namespace Paillave.Etl.EntityFrameworkCore +namespace Paillave.Etl.EntityFrameworkCore; + +public class EfCoreSaveArgsBuilder { - public class EfCoreSaveArgsBuilder + internal EfCoreSaveArgs Args { get; set; } + public EfCoreSaveArgsBuilder(IStream sourceStream, Func getEntity, Func getOutput, Type? dbContextType) { - internal EfCoreSaveArgs Args { get; set; } - public EfCoreSaveArgsBuilder(IStream sourceStream, Func getEntity, Func getOutput) - { - this.Args = new EfCoreSaveArgs - { - SourceStream = sourceStream, - GetEntity = getEntity, - GetOutput = getOutput - }; - } - private EfCoreSaveArgsBuilder(EfCoreSaveArgs args) + this.Args = new EfCoreSaveArgs { - this.Args = args; - } - private TArgs UpdateArgs(TArgs args) where TArgs : IThroughEntityFrameworkCoreArgs + SourceStream = sourceStream, + GetEntity = getEntity, + GetOutput = getOutput, + DbContextType = dbContextType + }; + } + private EfCoreSaveArgsBuilder(EfCoreSaveArgs args) + { + this.Args = args; + } + private TArgs UpdateArgs(TArgs args) where TArgs : IThroughEntityFrameworkCoreArgs + { + args.BatchSize = this.Args.BatchSize; + args.BulkLoadMode = this.Args.BulkLoadMode; + args.DoNotUpdateIfExists = this.Args.DoNotUpdateIfExists; + args.InsertOnly = this.Args.InsertOnly; + args.SourceStream = this.Args.SourceStream; + args.KeyedConnection = this.Args.KeyedConnection; + return args; + } + public EfCoreSaveArgsBuilder Entity(Func getEntity) where TNewInEf : class + => new EfCoreSaveArgsBuilder(UpdateArgs(new EfCoreSaveArgs { - args.BatchSize = this.Args.BatchSize; - args.BulkLoadMode = this.Args.BulkLoadMode; - args.DoNotUpdateIfExists = this.Args.DoNotUpdateIfExists; - args.InsertOnly = this.Args.InsertOnly; - args.SourceStream = this.Args.SourceStream; - args.KeyedConnection = this.Args.KeyedConnection; - return args; - } - public EfCoreSaveArgsBuilder Entity(Func getEntity) where TNewInEf : class - => new EfCoreSaveArgsBuilder(UpdateArgs(new EfCoreSaveArgs - { - GetEntity = getEntity, - GetOutput = (i, j) => j - })); + GetEntity = getEntity, + GetOutput = (i, j) => j + })); - public EfCoreSaveArgsBuilder SeekOn(Expression> pivot) - { - this.Args.PivotKeys = new List>> { pivot }; - return this; - } - public EfCoreSaveArgsBuilder AlternativelySeekOn(Expression> pivot) + public EfCoreSaveArgsBuilder SeekOn(Expression> pivot) + { + this.Args.PivotKeys = new List>> { pivot }; + return this; + } + public EfCoreSaveArgsBuilder AlternativelySeekOn(Expression> pivot) + { + this.Args.PivotKeys.Add(pivot); + return this; + } + public EfCoreSaveArgsBuilder Output(Func getOutput) + => new EfCoreSaveArgsBuilder(UpdateArgs(new EfCoreSaveArgs { - this.Args.PivotKeys.Add(pivot); - return this; - } - public EfCoreSaveArgsBuilder Output(Func getOutput) - => new EfCoreSaveArgsBuilder(UpdateArgs(new EfCoreSaveArgs - { - GetEntity = this.Args.GetEntity, - GetOutput = getOutput, - PivotKeys = this.Args.PivotKeys - })); + GetEntity = this.Args.GetEntity, + GetOutput = getOutput, + PivotKeys = this.Args.PivotKeys + })); - public EfCoreSaveArgsBuilder WithBatchSize(int batchSize) - { - this.Args.BatchSize = batchSize; - return this; - } - public EfCoreSaveArgsBuilder WithKeyedConnection(string keyedConnection) - { - this.Args.KeyedConnection = keyedConnection; - return this; - } - public EfCoreSaveArgsBuilder WithMode(SaveMode bulkLoadMode) - { - this.Args.BulkLoadMode = bulkLoadMode; - return this; - } - public EfCoreSaveArgsBuilder DoNotUpdateIfExists(bool doNotUpdateIfExists = true) - { - this.Args.DoNotUpdateIfExists = doNotUpdateIfExists; - return this; - } - public EfCoreSaveArgsBuilder InsertOnly(bool insertOnly = true) - { - this.Args.InsertOnly = insertOnly; - return this; - } + public EfCoreSaveArgsBuilder WithBatchSize(int batchSize) + { + this.Args.BatchSize = batchSize; + return this; + } + public EfCoreSaveArgsBuilder WithKeyedConnection(string keyedConnection) + { + this.Args.KeyedConnection = keyedConnection; + return this; + } + public EfCoreSaveArgsBuilder WithMode(SaveMode bulkLoadMode) + { + this.Args.BulkLoadMode = bulkLoadMode; + return this; + } + public EfCoreSaveArgsBuilder DoNotUpdateIfExists(bool doNotUpdateIfExists = true) + { + this.Args.DoNotUpdateIfExists = doNotUpdateIfExists; + return this; } + public EfCoreSaveArgsBuilder InsertOnly(bool insertOnly = true) + { + this.Args.InsertOnly = insertOnly; + return this; + } + public EfCoreSaveArgsBuilder WithContextType() where TContext : DbContext + { + this.Args.DbContextType = typeof(TContext); + return this; + } +} @@ -94,165 +101,222 @@ private EfCoreSaveArgsBuilder(EfCoreSaveArgs args) - public class EfCoreSaveCorrelatedArgsBuilder +public class EfCoreSaveCorrelatedArgsBuilder +{ + internal EfCoreSaveArgs, Correlated> Args { get; set; } + public EfCoreSaveCorrelatedArgsBuilder(IStream> sourceStream, Func getEntity, Func getOutput, Type? dbContextType) { - internal EfCoreSaveArgs, Correlated> Args { get; set; } - public EfCoreSaveCorrelatedArgsBuilder(IStream> sourceStream, Func getEntity, Func getOutput) + this.Args = new EfCoreSaveArgs, Correlated> { - this.Args = new EfCoreSaveArgs, Correlated> - { - SourceStream = sourceStream, - GetEntity = i => getEntity(i.Row), - GetOutput = (i, e) => new Correlated { Row = getOutput(i.Row, e), CorrelationKeys = i.CorrelationKeys } - }; - } - private EfCoreSaveCorrelatedArgsBuilder(EfCoreSaveArgs, Correlated> args) - { - this.Args = args; - } - private TArgs UpdateArgs(TArgs args) where TArgs : IThroughEntityFrameworkCoreArgs> + SourceStream = sourceStream, + GetEntity = i => getEntity(i.Row), + GetOutput = (i, e) => new Correlated { Row = getOutput(i.Row, e), CorrelationKeys = i.CorrelationKeys }, + DbContextType = dbContextType + }; + } + private EfCoreSaveCorrelatedArgsBuilder(EfCoreSaveArgs, Correlated> args) + { + this.Args = args; + } + private TArgs UpdateArgs(TArgs args) where TArgs : IThroughEntityFrameworkCoreArgs> + { + args.BatchSize = this.Args.BatchSize; + args.BulkLoadMode = this.Args.BulkLoadMode; + args.DoNotUpdateIfExists = this.Args.DoNotUpdateIfExists; + args.InsertOnly = this.Args.InsertOnly; + args.SourceStream = this.Args.SourceStream; + args.KeyedConnection = this.Args.KeyedConnection; + args.DbContextType = this.Args.DbContextType; + return args; + } + public EfCoreSaveCorrelatedArgsBuilder Entity(Func getEntity) where TNewInEf : class + => new EfCoreSaveCorrelatedArgsBuilder(UpdateArgs(new EfCoreSaveArgs, Correlated> { - args.BatchSize = this.Args.BatchSize; - args.BulkLoadMode = this.Args.BulkLoadMode; - args.DoNotUpdateIfExists = this.Args.DoNotUpdateIfExists; - args.InsertOnly = this.Args.InsertOnly; - args.SourceStream = this.Args.SourceStream; - args.KeyedConnection = this.Args.KeyedConnection; - return args; - } - public EfCoreSaveCorrelatedArgsBuilder Entity(Func getEntity) where TNewInEf : class - => new EfCoreSaveCorrelatedArgsBuilder(UpdateArgs(new EfCoreSaveArgs, Correlated> - { - GetEntity = i => getEntity(i.Row), - GetOutput = (i, j) => new Correlated { Row = j, CorrelationKeys = i.CorrelationKeys } - })); + GetEntity = i => getEntity(i.Row), + GetOutput = (i, j) => new Correlated { Row = j, CorrelationKeys = i.CorrelationKeys } + })); - public EfCoreSaveCorrelatedArgsBuilder SeekOn(Expression> pivot) - { - this.Args.PivotKeys = new List>> { pivot }; - return this; - } - public EfCoreSaveCorrelatedArgsBuilder AlternativelySeekOn(Expression> pivot) + public EfCoreSaveCorrelatedArgsBuilder SeekOn(Expression> pivot) + { + this.Args.PivotKeys = new List>> { pivot }; + return this; + } + public EfCoreSaveCorrelatedArgsBuilder AlternativelySeekOn(Expression> pivot) + { + this.Args.PivotKeys.Add(pivot); + return this; + } + public EfCoreSaveCorrelatedArgsBuilder Output(Func getOutput) + => new EfCoreSaveCorrelatedArgsBuilder(UpdateArgs(new EfCoreSaveArgs, Correlated> { - this.Args.PivotKeys.Add(pivot); - return this; - } - public EfCoreSaveCorrelatedArgsBuilder Output(Func getOutput) - => new EfCoreSaveCorrelatedArgsBuilder(UpdateArgs(new EfCoreSaveArgs, Correlated> - { - GetEntity = this.Args.GetEntity, - GetOutput = (i, e) => new Correlated { Row = getOutput(i.Row, e), CorrelationKeys = i.CorrelationKeys }, - PivotKeys = this.Args.PivotKeys - })); + GetEntity = this.Args.GetEntity, + GetOutput = (i, e) => new Correlated { Row = getOutput(i.Row, e), CorrelationKeys = i.CorrelationKeys }, + PivotKeys = this.Args.PivotKeys + })); - public EfCoreSaveCorrelatedArgsBuilder WithBatchSize(int batchSize) - { - this.Args.BatchSize = batchSize; - return this; - } - public EfCoreSaveCorrelatedArgsBuilder WithKeyedConnection(string keyedConnection) - { - this.Args.KeyedConnection = keyedConnection; - return this; - } - public EfCoreSaveCorrelatedArgsBuilder WithMode(SaveMode bulkLoadMode) - { - this.Args.BulkLoadMode = bulkLoadMode; - return this; - } - public EfCoreSaveCorrelatedArgsBuilder DoNotUpdateIfExists(bool doNotUpdateIfExists = true) - { - this.Args.DoNotUpdateIfExists = doNotUpdateIfExists; - return this; - } - public EfCoreSaveCorrelatedArgsBuilder InsertOnly(bool insertOnly = true) - { - this.Args.InsertOnly = insertOnly; - return this; - } + public EfCoreSaveCorrelatedArgsBuilder WithBatchSize(int batchSize) + { + this.Args.BatchSize = batchSize; + return this; } - - internal interface IThroughEntityFrameworkCoreArgs + public EfCoreSaveCorrelatedArgsBuilder WithKeyedConnection(string keyedConnection) + { + this.Args.KeyedConnection = keyedConnection; + return this; + } + public EfCoreSaveCorrelatedArgsBuilder WithMode(SaveMode bulkLoadMode) { - IStream SourceStream { get; set; } - int BatchSize { get; set; } - SaveMode BulkLoadMode { get; set; } - bool DoNotUpdateIfExists { get; set; } - bool InsertOnly { get; set; } - string KeyedConnection { get; set; } + this.Args.BulkLoadMode = bulkLoadMode; + return this; } - public class EfCoreSaveArgs : IThroughEntityFrameworkCoreArgs + public EfCoreSaveCorrelatedArgsBuilder DoNotUpdateIfExists(bool doNotUpdateIfExists = true) { - internal EfCoreSaveArgs() { } - public IStream SourceStream { get; set; } - public int BatchSize { get; set; } = 10000; - public SaveMode BulkLoadMode { get; set; } = SaveMode.SqlServerBulk; - public Func GetEntity { get; set; } - public Func GetOutput { get; set; } - public List>> PivotKeys { get; set; } - public bool DoNotUpdateIfExists { get; set; } = false; - public bool InsertOnly { get; set; } = false; - public string KeyedConnection { get; set; } = null; + this.Args.DoNotUpdateIfExists = doNotUpdateIfExists; + return this; } - public enum SaveMode + public EfCoreSaveCorrelatedArgsBuilder InsertOnly(bool insertOnly = true) { - EntityFrameworkCore, - SqlServerBulk, + this.Args.InsertOnly = insertOnly; + return this; } - public class EfCoreSaveStreamNode : StreamNodeBase, EfCoreSaveArgs> - where TInEf : class + public EfCoreSaveCorrelatedArgsBuilder WithContextType() where TContext : DbContext { - public override ProcessImpact PerformanceImpact => ProcessImpact.Heavy; + this.Args.DbContextType = typeof(TContext); + return this; + } +} - public override ProcessImpact MemoryFootPrint => ProcessImpact.Light; +internal interface IThroughEntityFrameworkCoreArgs +{ + IStream SourceStream { get; set; } + int BatchSize { get; set; } + SaveMode BulkLoadMode { get; set; } + bool DoNotUpdateIfExists { get; set; } + bool InsertOnly { get; set; } + string KeyedConnection { get; set; } + Type? DbContextType { get; set; } +} +public class EfCoreSaveArgs : IThroughEntityFrameworkCoreArgs +{ + internal EfCoreSaveArgs() { } + public IStream SourceStream { get; set; } + public int BatchSize { get; set; } = 10000; + public SaveMode BulkLoadMode { get; set; } = SaveMode.SqlServerBulk; + public Func GetEntity { get; set; } + public Func GetOutput { get; set; } + public List>> PivotKeys { get; set; } + public bool DoNotUpdateIfExists { get; set; } = false; + public bool InsertOnly { get; set; } = false; + public string? KeyedConnection { get; set; } = null; + public bool KeepChangeTracker { get; set; } = false; + public Type? DbContextType { get; set; } = null; +} +public enum SaveMode +{ + EntityFrameworkCore, + SqlServerBulk, +} +public class EfCoreSaveStreamNode : StreamNodeBase, EfCoreSaveArgs> + where TInEf : class +{ + public override ProcessImpact PerformanceImpact => ProcessImpact.Heavy; - public EfCoreSaveStreamNode(string name, EfCoreSaveArgs args) : base(name, args) - { - } + public override ProcessImpact MemoryFootPrint => ProcessImpact.Light; - protected override IStream CreateOutputStream(EfCoreSaveArgs args) + public EfCoreSaveStreamNode(string name, EfCoreSaveArgs args) : base(name, args) + { + } + + protected override IStream CreateOutputStream(EfCoreSaveArgs args) + { + var ret = args.SourceStream.Observable + .Chunk(args.BatchSize) + .Map(i => i.Select(j => (Input: j, Entity: args.GetEntity(j))).ToList()) + .Do(ProcessChunk) + .FlatMap((i, ct) => PushObservable.FromEnumerable(i, ct)) + .Map(i => args.GetOutput(i.Input, i.Entity)); + return base.CreateUnsortedStream(ret); + } + private void ProcessChunk(List<(TIn Input, TInEf Entity)> i) + { + using var dbContextWrapper = this.ResolveDbContext(); + this.ExecutionContext.InvokeInDedicatedThreadAsync(dbContextWrapper.Object, () => ProcessBatch(i, dbContextWrapper.Object, this.Args.BulkLoadMode)).Wait(); + } + private DisposeWrapper ResolveDbContext() + { + var dbContextType = this.Args.DbContextType ?? typeof(DbContext); + var dbContextFactoryType = typeof(IDbContextFactory<>).MakeGenericType(dbContextType); + // if (IDbContextFactory) + if (this.Args.KeyedConnection == null) { - var ret = args.SourceStream.Observable - .Chunk(args.BatchSize) - .Map(i => i.Select(j => (Input: j, Entity: args.GetEntity(j))).ToList()) - .Do(i => - { - var dbContext = args.KeyedConnection == null - ? this.ExecutionContext.DependencyResolver.Resolve() - : this.ExecutionContext.DependencyResolver.Resolve(args.KeyedConnection); - this.ExecutionContext.InvokeInDedicatedThreadAsync(dbContext, () => ProcessBatch(i, dbContext, args.BulkLoadMode)).Wait(); - }) - .FlatMap((i, ct) => PushObservable.FromEnumerable(i, ct)) - .Map(i => args.GetOutput(i.Input, i.Entity)); - return base.CreateUnsortedStream(ret); + if (this.ExecutionContext.DependencyResolver.TryResolve(dbContextType, out var dbContext)) + { + return new DisposeWrapper((DbContext)dbContext, false); + } + else if (this.ExecutionContext.DependencyResolver.TryResolve(dbContextFactoryType, out var dbContextFactory)) + { + var contextFactory = (DbContext)this.ExecutionContext.DependencyResolver.Resolve(dbContextType); + dbContext = dbContextFactoryType.GetMethod(nameof(IDbContextFactory.CreateDbContext))?.Invoke(contextFactory, null); + return new DisposeWrapper((DbContext)dbContext, true); + } + return null; } - public void ProcessBatch(List<(TIn Input, TInEf Entity)> items, DbContext dbContext, SaveMode bulkLoadMode) + else { - var entities = items.Select(i => i.Item2).ToArray(); - var pivotKeys = Args.PivotKeys == null ? (Expression>[])null : Args.PivotKeys.ToArray(); - if (bulkLoadMode == SaveMode.EntityFrameworkCore) + if (this.ExecutionContext.DependencyResolver.TryResolve(dbContextType, this.Args.KeyedConnection, out var dbContext)) { - dbContext.EfSaveAsync(entities, pivotKeys, Args.SourceStream.Observable.CancellationToken, Args.DoNotUpdateIfExists, Args.InsertOnly).Wait(); + return new DisposeWrapper((DbContext)dbContext, false); } - else + else if (this.ExecutionContext.DependencyResolver.TryResolve(dbContextFactoryType, this.Args.KeyedConnection, out var dbContextFactory)) { - if (dbContext.Database.IsSqlServer()) - dbContext.BulkSave(entities, pivotKeys, Args.SourceStream.Observable.CancellationToken, Args.DoNotUpdateIfExists, Args.InsertOnly); - else - dbContext.EfSaveAsync(entities, pivotKeys, Args.SourceStream.Observable.CancellationToken, Args.DoNotUpdateIfExists, Args.InsertOnly).Wait(); + var contextFactory = (DbContext)this.ExecutionContext.DependencyResolver.Resolve(dbContextType); + dbContext = dbContextFactoryType.GetMethod(nameof(IDbContextFactory.CreateDbContext))?.Invoke(contextFactory, null); + return new DisposeWrapper((DbContext)dbContext, true); } - DetachAllEntities(dbContext); + return null; } - public void DetachAllEntities(DbContext dbContext) + } + public async Task ProcessBatch(List<(TIn Input, TInEf Entity)> items, DbContext dbContext, SaveMode bulkLoadMode) + { + var entities = items.Select(i => i.Item2).ToArray(); + var pivotKeys = Args.PivotKeys == null ? (Expression>[])null : Args.PivotKeys.ToArray(); + if (bulkLoadMode == SaveMode.EntityFrameworkCore) { - var changedEntriesCopy = dbContext.ChangeTracker.Entries() - .Where(e => e.State == EntityState.Added || - e.State == EntityState.Modified || - e.State == EntityState.Deleted) - .ToList(); - - foreach (var entry in changedEntriesCopy) - entry.State = EntityState.Detached; + dbContext.EfSaveAsync(entities, pivotKeys, Args.SourceStream.Observable.CancellationToken, Args.DoNotUpdateIfExists, Args.InsertOnly).Wait(); } + else + { + if (dbContext.Database.IsSqlServer()) + dbContext.BulkSave(entities, pivotKeys, Args.SourceStream.Observable.CancellationToken, Args.DoNotUpdateIfExists, Args.InsertOnly); + else + dbContext.EfSaveAsync(entities, pivotKeys, Args.SourceStream.Observable.CancellationToken, Args.DoNotUpdateIfExists, Args.InsertOnly).Wait(); + } + DetachAllEntities(dbContext); + } + public void DetachAllEntities(DbContext dbContext) + { + var changedEntriesCopy = dbContext.ChangeTracker.Entries() + .Where(e => e.State == EntityState.Added || + e.State == EntityState.Modified || + e.State == EntityState.Deleted) + .ToList(); + + foreach (var entry in changedEntriesCopy) + entry.State = EntityState.Detached; + if (!Args.KeepChangeTracker) + dbContext.ChangeTracker.Clear(); + } +} +public class DisposeWrapper : IDisposable where T : IDisposable +{ + public T Object { get; } + private readonly bool _dispose; + public DisposeWrapper(T obj, bool dispose) + => (Object, _dispose) = (obj, dispose); + + public void Dispose() + { + if (_dispose) + this.Object.Dispose(); } } diff --git a/src/Paillave.Etl.EntityFrameworkCore/EntityFrameworkCoreSave.Stream.ex.cs b/src/Paillave.Etl.EntityFrameworkCore/EntityFrameworkCoreSave.Stream.ex.cs index 68b72d9e..96c9f888 100644 --- a/src/Paillave.Etl.EntityFrameworkCore/EntityFrameworkCoreSave.Stream.ex.cs +++ b/src/Paillave.Etl.EntityFrameworkCore/EntityFrameworkCoreSave.Stream.ex.cs @@ -10,29 +10,29 @@ public static class EntityFrameworkCoreSaveEx string name, Func, EfCoreSaveArgsBuilder> getOptions) where TInEf : class - => new EfCoreSaveStreamNode(name, getOptions(new EfCoreSaveArgsBuilder(stream, i => i, (i, j) => i)).Args).Output; + => new EfCoreSaveStreamNode(name, getOptions(new EfCoreSaveArgsBuilder(stream, i => i, (i, j) => i, null)).Args).Output; public static IStream> EfCoreSave( this IStream> stream, string name, Func, EfCoreSaveCorrelatedArgsBuilder> getOptions) where TInEf : class - => new EfCoreSaveStreamNode, Correlated>(name, getOptions(new EfCoreSaveCorrelatedArgsBuilder(stream, i => i, (i, j) => i)).Args).Output; + => new EfCoreSaveStreamNode, Correlated>(name, getOptions(new EfCoreSaveCorrelatedArgsBuilder(stream, i => i, (i, j) => i, null)).Args).Output; // copy/paste to explicitly solve ambiguity if any public static IStream> EfCoreSaveCorrelated( this IStream> stream, string name, Func, EfCoreSaveCorrelatedArgsBuilder> getOptions) where TInEf : class - => new EfCoreSaveStreamNode, Correlated>(name, getOptions(new EfCoreSaveCorrelatedArgsBuilder(stream, i => i, (i, j) => i)).Args).Output; + => new EfCoreSaveStreamNode, Correlated>(name, getOptions(new EfCoreSaveCorrelatedArgsBuilder(stream, i => i, (i, j) => i, null)).Args).Output; public static IStream EfCoreSave(this IStream stream, string name) where TIn : class - => new EfCoreSaveStreamNode(name, new EfCoreSaveArgsBuilder(stream, i => i, (i, j) => i).Args).Output; + => new EfCoreSaveStreamNode(name, new EfCoreSaveArgsBuilder(stream, i => i, (i, j) => i, null).Args).Output; public static IStream> EfCoreSave(this IStream> stream, string name) where TIn : class - => new EfCoreSaveStreamNode, Correlated>(name, new EfCoreSaveCorrelatedArgsBuilder(stream, i => i, (i, j) => i).Args).Output; + => new EfCoreSaveStreamNode, Correlated>(name, new EfCoreSaveCorrelatedArgsBuilder(stream, i => i, (i, j) => i, null).Args).Output; // copy/paste to explicitly solve ambiguity if any public static IStream> EfCoreSaveCorrelated(this IStream> stream, string name) where TIn : class - => new EfCoreSaveStreamNode, Correlated>(name, new EfCoreSaveCorrelatedArgsBuilder(stream, i => i, (i, j) => i).Args).Output; + => new EfCoreSaveStreamNode, Correlated>(name, new EfCoreSaveCorrelatedArgsBuilder(stream, i => i, (i, j) => i, null).Args).Output; } } \ No newline at end of file diff --git a/src/Paillave.Etl.EntityFrameworkCore/Paillave.Etl.EntityFrameworkCore.csproj b/src/Paillave.Etl.EntityFrameworkCore/Paillave.Etl.EntityFrameworkCore.csproj index c150f522..497f0cf4 100644 --- a/src/Paillave.Etl.EntityFrameworkCore/Paillave.Etl.EntityFrameworkCore.csproj +++ b/src/Paillave.Etl.EntityFrameworkCore/Paillave.Etl.EntityFrameworkCore.csproj @@ -1,7 +1,7 @@ Paillave.EtlNet.EntityFrameworkCore - 2.1.5-beta + 2.1.6-beta Stéphane Royer true diff --git a/src/Paillave.Etl.ExcelFile/Paillave.Etl.ExcelFile.csproj b/src/Paillave.Etl.ExcelFile/Paillave.Etl.ExcelFile.csproj index e0f60115..cd8f7347 100644 --- a/src/Paillave.Etl.ExcelFile/Paillave.Etl.ExcelFile.csproj +++ b/src/Paillave.Etl.ExcelFile/Paillave.Etl.ExcelFile.csproj @@ -1,7 +1,7 @@  Paillave.EtlNet.ExcelFile - 2.1.5-beta + 2.1.6-beta Stéphane Royer true diff --git a/src/Paillave.Etl.ExecutionToolkit/Paillave.Etl.ExecutionToolkit.csproj b/src/Paillave.Etl.ExecutionToolkit/Paillave.Etl.ExecutionToolkit.csproj index 36add9aa..8c634b64 100644 --- a/src/Paillave.Etl.ExecutionToolkit/Paillave.Etl.ExecutionToolkit.csproj +++ b/src/Paillave.Etl.ExecutionToolkit/Paillave.Etl.ExecutionToolkit.csproj @@ -1,7 +1,7 @@ Paillave.EtlNet.ExecutionToolkit - 2.1.5-beta + 2.1.6-beta Stéphane Royer true diff --git a/src/Paillave.Etl.FileSystem/Paillave.Etl.FileSystem.csproj b/src/Paillave.Etl.FileSystem/Paillave.Etl.FileSystem.csproj index c0a9235a..16e2ece7 100644 --- a/src/Paillave.Etl.FileSystem/Paillave.Etl.FileSystem.csproj +++ b/src/Paillave.Etl.FileSystem/Paillave.Etl.FileSystem.csproj @@ -1,7 +1,7 @@ Paillave.EtlNet.FileSystem - 2.1.5-beta + 2.1.6-beta Stéphane Royer true diff --git a/src/Paillave.Etl.FromConfigurationConnectors/Paillave.Etl.FromConfigurationConnectors.csproj b/src/Paillave.Etl.FromConfigurationConnectors/Paillave.Etl.FromConfigurationConnectors.csproj index 766777be..2293240a 100644 --- a/src/Paillave.Etl.FromConfigurationConnectors/Paillave.Etl.FromConfigurationConnectors.csproj +++ b/src/Paillave.Etl.FromConfigurationConnectors/Paillave.Etl.FromConfigurationConnectors.csproj @@ -1,7 +1,7 @@ Paillave.EtlNet.FromConfigurationConnectors - 2.1.5-beta + 2.1.6-beta Stéphane Royer true diff --git a/src/Paillave.Etl.Ftp/Paillave.Etl.Ftp.csproj b/src/Paillave.Etl.Ftp/Paillave.Etl.Ftp.csproj index 1f1e881b..7bd45bd7 100644 --- a/src/Paillave.Etl.Ftp/Paillave.Etl.Ftp.csproj +++ b/src/Paillave.Etl.Ftp/Paillave.Etl.Ftp.csproj @@ -1,7 +1,7 @@ Paillave.EtlNet.Ftp - 2.1.5-beta + 2.1.6-beta Stéphane Royer true diff --git a/src/Paillave.Etl.Mail/Paillave.Etl.Mail.csproj b/src/Paillave.Etl.Mail/Paillave.Etl.Mail.csproj index 832957f5..bba262b9 100644 --- a/src/Paillave.Etl.Mail/Paillave.Etl.Mail.csproj +++ b/src/Paillave.Etl.Mail/Paillave.Etl.Mail.csproj @@ -1,7 +1,7 @@ Paillave.EtlNet.Mail - 2.1.5-beta + 2.1.6-beta Stéphane Royer true diff --git a/src/Paillave.Etl.Pdf/Paillave.Etl.Pdf.csproj b/src/Paillave.Etl.Pdf/Paillave.Etl.Pdf.csproj index 1266d01e..92b8add2 100644 --- a/src/Paillave.Etl.Pdf/Paillave.Etl.Pdf.csproj +++ b/src/Paillave.Etl.Pdf/Paillave.Etl.Pdf.csproj @@ -1,7 +1,7 @@  Paillave.EtlNet.Pdf - 2.1.5-beta + 2.1.6-beta Stéphane Royer true diff --git a/src/Paillave.Etl.Sftp/Paillave.Etl.Sftp.csproj b/src/Paillave.Etl.Sftp/Paillave.Etl.Sftp.csproj index 0e8041c2..a42a148e 100644 --- a/src/Paillave.Etl.Sftp/Paillave.Etl.Sftp.csproj +++ b/src/Paillave.Etl.Sftp/Paillave.Etl.Sftp.csproj @@ -1,7 +1,7 @@ Paillave.EtlNet.Sftp - 2.1.5-beta + 2.1.6-beta Stéphane Royer true diff --git a/src/Paillave.Etl.SqlServer/Paillave.Etl.SqlServer.csproj b/src/Paillave.Etl.SqlServer/Paillave.Etl.SqlServer.csproj index c6c62906..199db29f 100644 --- a/src/Paillave.Etl.SqlServer/Paillave.Etl.SqlServer.csproj +++ b/src/Paillave.Etl.SqlServer/Paillave.Etl.SqlServer.csproj @@ -1,7 +1,7 @@ Paillave.EtlNet.SqlServer - 2.1.5-beta + 2.1.6-beta Stéphane Royer true diff --git a/src/Paillave.Etl.SqlServer/ToSqlCommandStreamNode.cs b/src/Paillave.Etl.SqlServer/ToSqlCommandStreamNode.cs index d24f5868..393307cc 100644 --- a/src/Paillave.Etl.SqlServer/ToSqlCommandStreamNode.cs +++ b/src/Paillave.Etl.SqlServer/ToSqlCommandStreamNode.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using Paillave.Etl.Reactive.Operators; using System.Linq; -using System.Data.SqlClient; using System.Reflection; using System.Text.RegularExpressions; using System.Data; diff --git a/src/Paillave.Etl.TextFile/Paillave.Etl.TextFile.csproj b/src/Paillave.Etl.TextFile/Paillave.Etl.TextFile.csproj index 9ce1a9f7..c363ff83 100644 --- a/src/Paillave.Etl.TextFile/Paillave.Etl.TextFile.csproj +++ b/src/Paillave.Etl.TextFile/Paillave.Etl.TextFile.csproj @@ -1,7 +1,7 @@ Paillave.EtlNet.TextFile - 2.1.5-beta + 2.1.6-beta Stéphane Royer true diff --git a/src/Paillave.Etl.XmlFile/Paillave.Etl.XmlFile.csproj b/src/Paillave.Etl.XmlFile/Paillave.Etl.XmlFile.csproj index 07afed58..0ff785a6 100644 --- a/src/Paillave.Etl.XmlFile/Paillave.Etl.XmlFile.csproj +++ b/src/Paillave.Etl.XmlFile/Paillave.Etl.XmlFile.csproj @@ -1,7 +1,7 @@ Paillave.EtlNet.XmlFile - 2.1.5-beta + 2.1.6-beta Stéphane Royer true diff --git a/src/Paillave.Etl.Zip/Paillave.Etl.Zip.csproj b/src/Paillave.Etl.Zip/Paillave.Etl.Zip.csproj index 5e0e20c7..b3af406e 100644 --- a/src/Paillave.Etl.Zip/Paillave.Etl.Zip.csproj +++ b/src/Paillave.Etl.Zip/Paillave.Etl.Zip.csproj @@ -1,7 +1,7 @@ Paillave.EtlNet.Zip - 2.1.5-beta + 2.1.6-beta Stéphane Royer true diff --git a/src/Paillave.Etl/Core/CompositeDependencyResolver.cs b/src/Paillave.Etl/Core/CompositeDependencyResolver.cs index 37462179..e1fb9528 100644 --- a/src/Paillave.Etl/Core/CompositeDependencyResolver.cs +++ b/src/Paillave.Etl/Core/CompositeDependencyResolver.cs @@ -74,6 +74,30 @@ public object Resolve(Type type) return false; } + public object Resolve(Type type, string key) + { + lock (_lock) + { + object resolved = default; + foreach (var dependencyResolver in _dependencyResolvers) + if (dependencyResolver.TryResolve(type, key, out resolved)) + return resolved; + } + return default; + } + + public bool TryResolve(Type type, string key, out object resolved) + { + lock (_lock) + { + resolved = default; + foreach (var dependencyResolver in _dependencyResolvers) + if (dependencyResolver.TryResolve(type, key, out resolved)) + return true; + } + return false; + } + public bool TryResolve(Type type, out object resolved) { lock (_lock) diff --git a/src/Paillave.Etl/Core/DummyDependencyResolver.cs b/src/Paillave.Etl/Core/DummyDependencyResolver.cs index 644d47bb..49ca55e0 100644 --- a/src/Paillave.Etl/Core/DummyDependencyResolver.cs +++ b/src/Paillave.Etl/Core/DummyDependencyResolver.cs @@ -9,6 +9,14 @@ public class DummyDependencyResolver : IDependencyResolver public T Resolve() where T : class => default; public T Resolve(string key) where T : class => default; + public object Resolve(Type type, string key) => default; + + public bool TryResolve(Type type, string key, out object resolved) + { + resolved = default; + return false; + } + public bool TryResolve(out T resolved) where T : class { resolved = default; diff --git a/src/Paillave.Etl/Core/IDependencyResolver.cs b/src/Paillave.Etl/Core/IDependencyResolver.cs index 804c38fb..700f3165 100644 --- a/src/Paillave.Etl/Core/IDependencyResolver.cs +++ b/src/Paillave.Etl/Core/IDependencyResolver.cs @@ -5,10 +5,17 @@ namespace Paillave.Etl.Core public interface IDependencyResolver { T Resolve() where T : class; - T Resolve(string key) where T : class; object Resolve(Type type); + bool TryResolve(out T resolved) where T : class; - bool TryResolve(string key, out T resolved) where T : class; bool TryResolve(Type type, out object resolved); + + + T Resolve(string key) where T : class; + object Resolve(Type type, string key); + + + bool TryResolve(string key, out T resolved) where T : class; + bool TryResolve(Type type, string key, out object resolved); } } \ No newline at end of file diff --git a/src/Paillave.Etl/Core/SimpleDependencyResolver.cs b/src/Paillave.Etl/Core/SimpleDependencyResolver.cs index 5a4ee8ab..979cb5bc 100644 --- a/src/Paillave.Etl/Core/SimpleDependencyResolver.cs +++ b/src/Paillave.Etl/Core/SimpleDependencyResolver.cs @@ -60,7 +60,7 @@ public T Resolve(Func creator) { lock (_lock) { - return (T)Resolve(key); + return (T)Resolve(typeof(T), key); } } public T Resolve() where T : class @@ -79,7 +79,7 @@ public object Resolve(Type type) } } - public object Resolve(string key) + public object Resolve(Type type, string key) { lock (_lock) { @@ -122,6 +122,23 @@ public object Resolve(string key) } } + public bool TryResolve(Type type, string key, out object resolved) + { + lock (_lock) + { + if (this._namedDictionary.TryGetValue(key, out var res)) + { + resolved = res; + return true; + } + else + { + resolved = default; + } + return false; + } + } + public bool TryResolve(Type type, out object resolved) { lock (_lock) diff --git a/src/Paillave.Etl/Paillave.Etl.csproj b/src/Paillave.Etl/Paillave.Etl.csproj index 0be2c0f4..378395b4 100644 --- a/src/Paillave.Etl/Paillave.Etl.csproj +++ b/src/Paillave.Etl/Paillave.Etl.csproj @@ -1,7 +1,7 @@  Paillave.EtlNet.Core - 2.1.5-beta + 2.1.6-beta Stéphane Royer true diff --git a/src/Paillave.Pdf/Paillave.Pdf.csproj b/src/Paillave.Pdf/Paillave.Pdf.csproj index 87fbf4f8..f8a7be4f 100644 --- a/src/Paillave.Pdf/Paillave.Pdf.csproj +++ b/src/Paillave.Pdf/Paillave.Pdf.csproj @@ -1,7 +1,7 @@ Paillave.Pdf - 2.1.5-beta + 2.1.6-beta Stéphane Royer true