diff --git a/src/Paillave.EntityFrameworkCoreExtension/EfSave/EfSaveEngine.cs b/src/Paillave.EntityFrameworkCoreExtension/EfSave/EfSaveEngine.cs index c5751dde..1bf91e58 100644 --- a/src/Paillave.EntityFrameworkCoreExtension/EfSave/EfSaveEngine.cs +++ b/src/Paillave.EntityFrameworkCoreExtension/EfSave/EfSaveEngine.cs @@ -92,10 +92,6 @@ private void InsertOrUpdateEntity(bool doNotUpdateIfExists, DbSet contextSet, { var entityCondition = _findConditionExpression.ApplyPartialLeft(entity); var existingEntity = contextSet.AsNoTracking().FirstOrDefault(entityCondition); - if (this._context is MultiTenantDbContext mtCtx) - { - mtCtx.UpdateEntityForMultiTenancy(entity); - } if (existingEntity == null) { _context.Entry(entity).State = EntityState.Added; @@ -107,10 +103,14 @@ private void InsertOrUpdateEntity(bool doNotUpdateIfExists, DbSet contextSet, var val = keyPropertyInfo.GetValue(existingEntity); keyPropertyInfo.SetValue(entity, val); } - if (!doNotUpdateIfExists) - { - contextSet.Update(entity); - } + } + if (this._context is MultiTenantDbContext mtCtx) + { + mtCtx.UpdateEntityForMultiTenancy(entity); + } + if (existingEntity != null && !doNotUpdateIfExists) + { + contextSet.Update(entity); } } } diff --git a/src/Paillave.Etl.Autofac/AutofacDependencyResolver.cs b/src/Paillave.Etl.Autofac/AutofacDependencyResolver.cs index 12e92681..d9851985 100644 --- a/src/Paillave.Etl.Autofac/AutofacDependencyResolver.cs +++ b/src/Paillave.Etl.Autofac/AutofacDependencyResolver.cs @@ -2,68 +2,66 @@ using Autofac; using Paillave.Etl.Core; -namespace Paillave.Etl.Autofac +namespace Paillave.Etl.Autofac; +public class AutofacDependencyResolver : IDependencyResolver { - public class AutofacDependencyResolver : IDependencyResolver + private SimpleDependencyResolver _dependencyResolver = new SimpleDependencyResolver(); + private readonly IComponentContext _componentContext; + public AutofacDependencyResolver(IComponentContext componentContext) => (_componentContext) = (componentContext); + public object Resolve(Type type) { - private SimpleDependencyResolver _dependencyResolver = new SimpleDependencyResolver(); - private readonly IComponentContext _componentContext; - public AutofacDependencyResolver(IComponentContext componentContext) => (_componentContext) = (componentContext); - public object Resolve(Type type) - { - var res = _dependencyResolver.Resolve(type); - if (res != null) return res; - res = _componentContext.Resolve(type); - _dependencyResolver.Register(type, res); - return res; - } - public T Resolve() where T : class - { - var res = _dependencyResolver.Resolve(); - if (res != null) return res; - res = _componentContext.Resolve(); - _dependencyResolver.Register(res); - return res; - } - public T Resolve(string key) where T : class - { - var res = _dependencyResolver.Resolve(key); - if (res != null) return res; - res = _componentContext.ResolveKeyed(key); - _dependencyResolver.Register(res, key); - return res; - } + var res = _dependencyResolver.Resolve(type); + if (res != null) return res; + res = _componentContext.Resolve(type); + _dependencyResolver.Register(type, res); + return res; + } + public T Resolve() where T : class + { + var res = _dependencyResolver.Resolve(); + if (res != null) return res; + res = _componentContext.Resolve(); + _dependencyResolver.Register(res); + return res; + } + public T Resolve(string key) where T : class + { + var res = _dependencyResolver.Resolve(key); + if (res != null) return res; + res = _componentContext.ResolveKeyed(key); + _dependencyResolver.Register(res, key); + return res; + } - public bool TryResolve(out T resolved) where T : class - { - resolved = default; - return _componentContext.TryResolve(out resolved); - } + public bool TryResolve(out T resolved) where T : class + { + resolved = default; + return _componentContext.TryResolve(out resolved); + } - public bool TryResolve(string key, out T resolved) where T : class - { - resolved = default; - return _componentContext.TryResolveKeyed(key, out resolved); - } + public bool TryResolve(string key, out T resolved) where T : class + { + resolved = default; + return _componentContext.TryResolveKeyed(key, out resolved); + } - public bool TryResolve(Type type, out object resolved) - { - return _componentContext.TryResolve(type, out resolved); - } + 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 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); - } + 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.XmlFile/Core/XmlObjectReaderV2.cs b/src/Paillave.Etl.XmlFile/Core/XmlObjectReaderV2.cs index fb13b02a..fbc9438c 100644 --- a/src/Paillave.Etl.XmlFile/Core/XmlObjectReaderV2.cs +++ b/src/Paillave.Etl.XmlFile/Core/XmlObjectReaderV2.cs @@ -70,8 +70,7 @@ private class PropertyBag public IXmlNodeDefinition XmlNodeDefinition { get; } private readonly List _xmlFieldDefinitions; private readonly HashSet _valuesPath; - private readonly Dictionary _xmlValues = new Dictionary(); - + private readonly Dictionary _xmlValues = new(); public PropertyBag(string sourceName, IXmlNodeDefinition xmlNodeDefinition) { SourceName = sourceName; @@ -79,15 +78,36 @@ public PropertyBag(string sourceName, IXmlNodeDefinition xmlNodeDefinition) _xmlFieldDefinitions = xmlNodeDefinition.GetXmlFieldDefinitions().ToList(); this._valuesPath = _xmlFieldDefinitions.Select(i => i.NodePath).ToHashSet(); } - public void SetValue(string key, string? value) { if (string.IsNullOrWhiteSpace(value)) return; - + // ^(?/(?[^/[]+)([[](?(?[^]=]+)=""(?[^""]*)"")[]])?)+$ + // /zer[sdfsdfsd="er"]/wfxf/trtr[qdff="bg"] + // https://regex101.com/r/tG1jF6/1 +// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX if (_valuesPath.Contains(key)) _xmlValues[key] = value; } + + // public void SetValue(string key, string? value, Dictionary xmlAttributes) + // { + // if (string.IsNullOrWhiteSpace(value)) + // return; + // if (TryGetPathMatch(key, xmlAttributes, out var pathMatch) && pathMatch != null) + // _xmlValues[pathMatch] = value; + // } + // private bool TryGetPathMatch(string key, Dictionary xmlAttributes, out string? pathMatch) + // { + // pathMatch = null; + // if (_valuesPath.Contains(key)) + // { + // pathMatch = key; + // return true; + // } + // return false; + // } + public object CreateRow() { var objectBuilder = new ObjectBuilder(XmlNodeDefinition.Type); diff --git a/src/Paillave.Etl.XmlFileTests/XmlObjectReaderV2Test.cs b/src/Paillave.Etl.XmlFileTests/XmlObjectReaderV2Test.cs index b3f9ca2a..bddc016f 100644 --- a/src/Paillave.Etl.XmlFileTests/XmlObjectReaderV2Test.cs +++ b/src/Paillave.Etl.XmlFileTests/XmlObjectReaderV2Test.cs @@ -11,6 +11,98 @@ namespace Paillave.Etl.XmlFileTests; public class XmlObjectReaderV2Tests { + // [Fact] + // public void Read_SimpleXmlWithAttributes_ParsesCorrectly3() + // { + // // Arrange + // var xml = @" + // + // root data + // + // 30 + // + // 123 Main St + // Springfield + // + // + // + // 32 + // + // + // 32 + // + // Big City + // + // + // "; + + // var definition = new XmlFileDefinition(); + // definition.AddNodeDefinition( + // "person", + // "/root/person", + // i => new TestPerson + // { + // Id = i.ToXPathQuery("/root/person/@id"), + // FirstName = i.ToXPathQuery("/root/person/@firstName"), + // LastName = i.ToXPathQuery("/root/person/@lastName"), + // Age = i.ToXPathQuery("/root/person/age"), + // Street = i.ToXPathQuery(@"/root/person/extraFields/field[@name=""street""]"), + // City = i.ToXPathQuery(@"/root/person/extraFields/field[@name=""city""]"), + // RootId = i.ToXPathQuery("/root/@rootId"), + // RootData = i.ToXPathQuery("/root/data"), + // }); + // definition.AddNodeDefinition( + // "company", + // "/root/company", + // i => new TestCompany + // { + // Id = i.ToXPathQuery("/root/company/@id"), + // Name = i.ToXPathQuery("/root/company/@name"), + // Street = i.ToXPathQuery(@"/root/company/extraFields/field[@name=""street""]"), + // City = i.ToXPathQuery(@"/root/company/extraFields/field[@name=""city""]"), + // RootId = i.ToXPathQuery("/root/@rootId"), + // RootData = i.ToXPathQuery("/root/data"), + // }); + + // var results = new List(); + // var reader = new XmlObjectReaderV2(definition, "test", results.Add); + + // // Act + // using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xml))) + // { + // reader.Read(stream, CancellationToken.None); + // } + + // var people = results.FindAll(i => i.NodeDefinitionName == "person").ToList(); + // var person1 = people[0].Value as TestPerson; + // Assert.Equal(1, person1.Id); + // Assert.Equal("John", person1.FirstName); + // Assert.Equal("Doe", person1.LastName); + // Assert.Equal(30, person1.Age); + // Assert.Equal("123 Main St", person1.Street); + // Assert.Equal("Springfield", person1.City); + // Assert.Equal("a root id", person1.RootId); + // Assert.Equal("root data", person1.RootData); + // var person2 = results[1].Value as TestPerson; + // Assert.Equal(2, person2.Id); + // Assert.Equal("Coucou", person2.FirstName); + // Assert.Null(person2.LastName); + // Assert.Equal(32, person2.Age); + // Assert.Null(person2.Street); + // Assert.Null(person2.City); + // Assert.Equal("a root id", person2.RootId); + // Assert.Equal("root data", person2.RootData); + + // var companies = results.FindAll(i => i.NodeDefinitionName == "company").ToList(); + // var company1 = companies[0].Value as TestCompany; + // Assert.Equal(3, company1.Id); + // Assert.Equal("MyCompany", company1.Name); + // Assert.Null(company1.Street); + // Assert.Equal("Big City", company1.City); + // Assert.Equal("a root id", company1.RootId); + // Assert.Equal("root data", company1.RootData); + // } + [Fact] public void Read_SimpleXmlWithAttributes_ParsesCorrectly2() { diff --git a/src/SharedSettings.props b/src/SharedSettings.props index 2f7ff0ae..807fe6a4 100644 --- a/src/SharedSettings.props +++ b/src/SharedSettings.props @@ -2,7 +2,7 @@ latest enable - 2.1.36-beta + 2.1.37-beta NugetIcon.png README.md Stéphane Royer diff --git a/src/Tutorials/Paillave.Etl.Samples/DataAccess/SimpleTable.cs b/src/Tutorials/Paillave.Etl.Samples/DataAccess/SimpleTable.cs new file mode 100644 index 00000000..a4851974 --- /dev/null +++ b/src/Tutorials/Paillave.Etl.Samples/DataAccess/SimpleTable.cs @@ -0,0 +1,21 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Paillave.Etl.Samples.DataAccess +{ + public class SimpleTable + { + public int Id { get; set; } + public string Name { get; set; } + } + public class SimpleTableConfiguration : IEntityTypeConfiguration + { + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable(nameof(SimpleTable)); + builder.HasKey(i => i.Id); + builder.Property(i => i.Id).UseIdentityColumn(); + } + } +} \ No newline at end of file diff --git a/src/Tutorials/Paillave.Etl.Samples/Migrations/20201030083250_TestDb.Designer.cs b/src/Tutorials/Paillave.Etl.Samples/Migrations/20241127170031_Initial.Designer.cs similarity index 73% rename from src/Tutorials/Paillave.Etl.Samples/Migrations/20201030083250_TestDb.Designer.cs rename to src/Tutorials/Paillave.Etl.Samples/Migrations/20241127170031_Initial.Designer.cs index da49cde0..f20e8354 100644 --- a/src/Tutorials/Paillave.Etl.Samples/Migrations/20201030083250_TestDb.Designer.cs +++ b/src/Tutorials/Paillave.Etl.Samples/Migrations/20241127170031_Initial.Designer.cs @@ -7,28 +7,31 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Paillave.Etl.Samples.DataAccess; +#nullable disable + namespace Paillave.Etl.Samples.Migrations { [DbContext(typeof(TestDbContext))] - [Migration("20201030083250_TestDb")] - partial class TestDb + [Migration("20241127170031_Initial")] + partial class Initial { + /// protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "3.1.9") - .HasAnnotation("Relational:MaxIdentifierLength", 128) - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasAnnotation("ProductVersion", "7.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); modelBuilder.Entity("Paillave.Etl.Samples.DataAccess.Composition", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("int") - .HasAnnotation("SqlServer:IdentityIncrement", 1) - .HasAnnotation("SqlServer:IdentitySeed", 1) - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); b.Property("Date") .HasColumnType("DATE"); @@ -42,23 +45,23 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.HasIndex("PortfolioId"); - b.ToTable("Composition"); + b.ToTable("Composition", (string)null); }); modelBuilder.Entity("Paillave.Etl.Samples.DataAccess.Portfolio", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("int") - .HasAnnotation("SqlServer:IdentityIncrement", 1) - .HasAnnotation("SqlServer:IdentitySeed", 1) - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); b.Property("InternalCode") .IsRequired() .HasColumnType("nvarchar(450)"); b.Property("Name") + .IsRequired() .HasColumnType("nvarchar(max)"); b.Property("SicavId") @@ -70,7 +73,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.HasIndex("SicavId"); - b.ToTable("Portfolio"); + b.ToTable("Portfolio", (string)null); }); modelBuilder.Entity("Paillave.Etl.Samples.DataAccess.Position", b => @@ -88,17 +91,16 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.HasIndex("SecurityId"); - b.ToTable("Position"); + b.ToTable("Position", (string)null); }); modelBuilder.Entity("Paillave.Etl.Samples.DataAccess.Security", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("int") - .HasAnnotation("SqlServer:IdentityIncrement", 1) - .HasAnnotation("SqlServer:IdentitySeed", 1) - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); b.Property("Discriminator") .IsRequired() @@ -109,34 +111,38 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .HasColumnType("nvarchar(450)"); b.Property("Isin") + .IsRequired() .HasColumnType("nvarchar(max)"); b.Property("Name") + .IsRequired() .HasColumnType("nvarchar(max)"); b.HasKey("Id"); b.HasAlternateKey("InternalCode"); - b.ToTable("Security"); + b.ToTable("Security", (string)null); b.HasDiscriminator("Discriminator").HasValue("Security"); + + b.UseTphMappingStrategy(); }); modelBuilder.Entity("Paillave.Etl.Samples.DataAccess.Sicav", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("int") - .HasAnnotation("SqlServer:IdentityIncrement", 1) - .HasAnnotation("SqlServer:IdentitySeed", 1) - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); b.Property("InternalCode") .IsRequired() .HasColumnType("nvarchar(450)"); b.Property("Name") + .IsRequired() .HasColumnType("nvarchar(max)"); b.Property("Type") @@ -146,7 +152,24 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.HasAlternateKey("InternalCode"); - b.ToTable("Sicav"); + b.ToTable("Sicav", (string)null); + }); + + modelBuilder.Entity("Paillave.Etl.Samples.DataAccess.SimpleTable", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("SimpleTable", (string)null); }); modelBuilder.Entity("Paillave.Etl.Samples.DataAccess.Equity", b => @@ -178,6 +201,8 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .HasForeignKey("PortfolioId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Portfolio"); }); modelBuilder.Entity("Paillave.Etl.Samples.DataAccess.Portfolio", b => @@ -187,6 +212,8 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .HasForeignKey("SicavId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Sicav"); }); modelBuilder.Entity("Paillave.Etl.Samples.DataAccess.Position", b => @@ -202,6 +229,15 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .HasForeignKey("SecurityId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Composition"); + + b.Navigation("Security"); + }); + + modelBuilder.Entity("Paillave.Etl.Samples.DataAccess.Composition", b => + { + b.Navigation("Positions"); }); #pragma warning restore 612, 618 } diff --git a/src/Tutorials/Paillave.Etl.Samples/Migrations/20201030083250_TestDb.cs b/src/Tutorials/Paillave.Etl.Samples/Migrations/20241127170031_Initial.cs similarity index 65% rename from src/Tutorials/Paillave.Etl.Samples/Migrations/20201030083250_TestDb.cs rename to src/Tutorials/Paillave.Etl.Samples/Migrations/20241127170031_Initial.cs index 0cb8aec0..c2076c5e 100644 --- a/src/Tutorials/Paillave.Etl.Samples/Migrations/20201030083250_TestDb.cs +++ b/src/Tutorials/Paillave.Etl.Samples/Migrations/20241127170031_Initial.cs @@ -1,24 +1,28 @@ using System; using Microsoft.EntityFrameworkCore.Migrations; +#nullable disable + namespace Paillave.Etl.Samples.Migrations { - public partial class TestDb : Migration + /// + public partial class Initial : Migration { + /// protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.CreateTable( name: "Security", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), - InternalCode = table.Column(nullable: false), - Isin = table.Column(nullable: true), - Name = table.Column(nullable: true), - Discriminator = table.Column(nullable: false), - Issuer = table.Column(nullable: true), - Class = table.Column(nullable: true) + InternalCode = table.Column(type: "nvarchar(450)", nullable: false), + Isin = table.Column(type: "nvarchar(max)", nullable: false), + Name = table.Column(type: "nvarchar(max)", nullable: false), + Discriminator = table.Column(type: "nvarchar(max)", nullable: false), + Issuer = table.Column(type: "nvarchar(max)", nullable: true), + Class = table.Column(type: "nvarchar(max)", nullable: true) }, constraints: table => { @@ -30,11 +34,11 @@ protected override void Up(MigrationBuilder migrationBuilder) name: "Sicav", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), - InternalCode = table.Column(nullable: false), - Name = table.Column(nullable: true), - Type = table.Column(nullable: true) + InternalCode = table.Column(type: "nvarchar(450)", nullable: false), + Name = table.Column(type: "nvarchar(max)", nullable: false), + Type = table.Column(type: "nvarchar(max)", nullable: true) }, constraints: table => { @@ -42,15 +46,28 @@ protected override void Up(MigrationBuilder migrationBuilder) table.UniqueConstraint("AK_Sicav_InternalCode", x => x.InternalCode); }); + migrationBuilder.CreateTable( + name: "SimpleTable", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Name = table.Column(type: "nvarchar(max)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SimpleTable", x => x.Id); + }); + migrationBuilder.CreateTable( name: "Portfolio", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), - InternalCode = table.Column(nullable: false), - Name = table.Column(nullable: true), - SicavId = table.Column(nullable: false) + InternalCode = table.Column(type: "nvarchar(450)", nullable: false), + Name = table.Column(type: "nvarchar(max)", nullable: false), + SicavId = table.Column(type: "int", nullable: false) }, constraints: table => { @@ -68,10 +85,10 @@ protected override void Up(MigrationBuilder migrationBuilder) name: "Composition", columns: table => new { - Id = table.Column(nullable: false) + Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), Date = table.Column(type: "DATE", nullable: false), - PortfolioId = table.Column(nullable: false) + PortfolioId = table.Column(type: "int", nullable: false) }, constraints: table => { @@ -89,9 +106,9 @@ protected override void Up(MigrationBuilder migrationBuilder) name: "Position", columns: table => new { - CompositionId = table.Column(nullable: false), - SecurityId = table.Column(nullable: false), - Value = table.Column(nullable: false) + CompositionId = table.Column(type: "int", nullable: false), + SecurityId = table.Column(type: "int", nullable: false), + Value = table.Column(type: "decimal(18,2)", nullable: false) }, constraints: table => { @@ -126,11 +143,15 @@ protected override void Up(MigrationBuilder migrationBuilder) column: "SecurityId"); } + /// protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( name: "Position"); + migrationBuilder.DropTable( + name: "SimpleTable"); + migrationBuilder.DropTable( name: "Composition"); diff --git a/src/Tutorials/Paillave.Etl.Samples/Migrations/TestDbContextModelSnapshot.cs b/src/Tutorials/Paillave.Etl.Samples/Migrations/TestDbContextModelSnapshot.cs index 541142b3..623d85b7 100644 --- a/src/Tutorials/Paillave.Etl.Samples/Migrations/TestDbContextModelSnapshot.cs +++ b/src/Tutorials/Paillave.Etl.Samples/Migrations/TestDbContextModelSnapshot.cs @@ -6,6 +6,8 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Paillave.Etl.Samples.DataAccess; +#nullable disable + namespace Paillave.Etl.Samples.Migrations { [DbContext(typeof(TestDbContext))] @@ -15,18 +17,18 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "3.1.9") - .HasAnnotation("Relational:MaxIdentifierLength", 128) - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasAnnotation("ProductVersion", "7.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); modelBuilder.Entity("Paillave.Etl.Samples.DataAccess.Composition", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("int") - .HasAnnotation("SqlServer:IdentityIncrement", 1) - .HasAnnotation("SqlServer:IdentitySeed", 1) - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); b.Property("Date") .HasColumnType("DATE"); @@ -40,23 +42,23 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("PortfolioId"); - b.ToTable("Composition"); + b.ToTable("Composition", (string)null); }); modelBuilder.Entity("Paillave.Etl.Samples.DataAccess.Portfolio", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("int") - .HasAnnotation("SqlServer:IdentityIncrement", 1) - .HasAnnotation("SqlServer:IdentitySeed", 1) - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); b.Property("InternalCode") .IsRequired() .HasColumnType("nvarchar(450)"); b.Property("Name") + .IsRequired() .HasColumnType("nvarchar(max)"); b.Property("SicavId") @@ -68,7 +70,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("SicavId"); - b.ToTable("Portfolio"); + b.ToTable("Portfolio", (string)null); }); modelBuilder.Entity("Paillave.Etl.Samples.DataAccess.Position", b => @@ -86,17 +88,16 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("SecurityId"); - b.ToTable("Position"); + b.ToTable("Position", (string)null); }); modelBuilder.Entity("Paillave.Etl.Samples.DataAccess.Security", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("int") - .HasAnnotation("SqlServer:IdentityIncrement", 1) - .HasAnnotation("SqlServer:IdentitySeed", 1) - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); b.Property("Discriminator") .IsRequired() @@ -107,34 +108,38 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("nvarchar(450)"); b.Property("Isin") + .IsRequired() .HasColumnType("nvarchar(max)"); b.Property("Name") + .IsRequired() .HasColumnType("nvarchar(max)"); b.HasKey("Id"); b.HasAlternateKey("InternalCode"); - b.ToTable("Security"); + b.ToTable("Security", (string)null); b.HasDiscriminator("Discriminator").HasValue("Security"); + + b.UseTphMappingStrategy(); }); modelBuilder.Entity("Paillave.Etl.Samples.DataAccess.Sicav", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("int") - .HasAnnotation("SqlServer:IdentityIncrement", 1) - .HasAnnotation("SqlServer:IdentitySeed", 1) - .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); b.Property("InternalCode") .IsRequired() .HasColumnType("nvarchar(450)"); b.Property("Name") + .IsRequired() .HasColumnType("nvarchar(max)"); b.Property("Type") @@ -144,7 +149,24 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasAlternateKey("InternalCode"); - b.ToTable("Sicav"); + b.ToTable("Sicav", (string)null); + }); + + modelBuilder.Entity("Paillave.Etl.Samples.DataAccess.SimpleTable", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("SimpleTable", (string)null); }); modelBuilder.Entity("Paillave.Etl.Samples.DataAccess.Equity", b => @@ -176,6 +198,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasForeignKey("PortfolioId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Portfolio"); }); modelBuilder.Entity("Paillave.Etl.Samples.DataAccess.Portfolio", b => @@ -185,6 +209,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasForeignKey("SicavId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Sicav"); }); modelBuilder.Entity("Paillave.Etl.Samples.DataAccess.Position", b => @@ -200,6 +226,15 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasForeignKey("SecurityId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + + b.Navigation("Composition"); + + b.Navigation("Security"); + }); + + modelBuilder.Entity("Paillave.Etl.Samples.DataAccess.Composition", b => + { + b.Navigation("Positions"); }); #pragma warning restore 612, 618 } diff --git a/src/Tutorials/Paillave.Etl.Samples/Program2.cs b/src/Tutorials/Paillave.Etl.Samples/Program2.cs index 5bc7ae3b..6385685b 100644 --- a/src/Tutorials/Paillave.Etl.Samples/Program2.cs +++ b/src/Tutorials/Paillave.Etl.Samples/Program2.cs @@ -10,6 +10,7 @@ using Paillave.Etl.Sftp; using Paillave.Etl.Mail; using Paillave.Etl.Zip; +using Microsoft.EntityFrameworkCore; namespace Paillave.Etl.Samples { @@ -56,11 +57,12 @@ static async Task ImportAndCreateFileAsync(string[] args) { var processRunner = StreamProcessRunner.Create(TestImport2.Import); var structure = processRunner.GetDefinitionStructure(); - structure.OpenEstimatedExecutionPlan(); + // structure.OpenEstimatedExecutionPlan(); ITraceReporter traceReporter = new AdvancedConsoleExecutionDisplay(); - var dataAccess= new DataAccess.TestDbContext(); + var dataAccess = new DataAccess.TestDbContext(); await dataAccess.Database.EnsureCreatedAsync(); + // dataAccess.Database.Migrate(); var executionOptions = new ExecutionOptions { Connectors = new FileValueConnectors() @@ -85,7 +87,7 @@ static async Task ImportAndCreateFileAsync(string[] args) static async Task ImportAndCreateFileWithConfigAsync(string[] args) { var processRunner = StreamProcessRunner.Create(TestImport2.Import); - var dataAccess= new DataAccess.TestDbContext(); + var dataAccess = new DataAccess.TestDbContext(); await dataAccess.Database.EnsureCreatedAsync(); var executionOptions = new ExecutionOptions { diff --git a/src/Tutorials/Paillave.Etl.Samples/TestImport3.cs b/src/Tutorials/Paillave.Etl.Samples/TestImport3.cs new file mode 100644 index 00000000..73f9ad80 --- /dev/null +++ b/src/Tutorials/Paillave.Etl.Samples/TestImport3.cs @@ -0,0 +1,19 @@ +using Paillave.Etl.EntityFrameworkCore; +using Paillave.Etl.Core; +using Paillave.Etl.TextFile; + +namespace Paillave.Etl.Samples; + +public static class TestImport3 +{ + public static void Import(ISingleStream contextStream) + { + var portfolioFileStream = contextStream + .FromConnector("Get portfolio files", "PTF") + .CrossApplyTextFile("Parse portfolio file", o => o + .UseMap(i => new DataAccess.SimpleTable { Name = i.ToColumn("SicavName") }).IsColumnSeparated(',')); + var sicavStream = portfolioFileStream + .Distinct("Distinct sicav", i => i.Name, true) + .EfCoreSave("Save sicav", o => o.WithMode(SaveMode.EntityFrameworkCore)); + } +}