Code Monkey home page Code Monkey logo

postgresqlcopyhelper's Introduction

PostgreSQLCopyHelper

Build Status stable prerelease

PostgreSQLCopyHelper is a library for efficient bulk inserts to PostgreSQL databases. It wraps the COPY methods from Npgsql behind a nice Fluent API.

Installing

To install PostgreSQLCopyHelper, run the following command in the Package Manager Console:

PM> Install-Package PostgreSQLCopyHelper

Basic Usage

Imagine we have the following table we want to copy data to:

CREATE TABLE sample.unit_test
(
	col_smallint smallint,
	col_integer integer,
	col_money money,
	col_bigint bigint,
	col_timestamp timestamp,
	col_real real,
	col_double double precision,
	col_bytea bytea,
	col_uuid uuid,
	col_numeric numeric,
	col_inet inet,
	col_macaddr macaddr,
	col_date date,
	col_interval interval
);

The corresponding domain model in our application could look like this:

private class TestEntity
{
	public Int16? SmallInt { get; set; }
	public Int32? Integer { get; set; }
	public Int64? BigInt { get; set; }
	public Decimal? Money { get; set; }
	public DateTime? Timestamp { get; set; }
	public Decimal? Numeric { get; set; }
	public Single? Real { get; set; }
	public Double? DoublePrecision { get; set; }
	public byte[] ByteArray { get; set; }
	public Guid? UUID { get; set; }
	public IPAddress IpAddress { get; set; }
	public PhysicalAddress MacAddress { get; set; }
	public DateTime? Date { get; set; }
	public TimeSpan? TimeSpan { get; set; }
}

The PostgreSQLCopyHelper now defines the mapping between domain model and the database table:

var copyHelper = new PostgreSQLCopyHelper<TestEntity>("sample", "unit_test")
	.MapSmallInt("col_smallint", x => x.SmallInt)
	.MapInteger("col_integer", x => x.Integer)
	.MapMoney("col_money", x => x.Money)
	.MapBigInt("col_bigint", x => x.BigInt)
	.MapTimeStamp("col_timestamp", x => x.Timestamp)
	.MapReal("col_real", x => x.Real)
	.MapDouble("col_double", x => x.DoublePrecision)
	.MapByteArray("col_bytea", x => x.ByteArray)
	.MapUUID("col_uuid", x => x.UUID)
	.MapInetAddress("col_inet", x => x.IpAddress)
	.MapMacAddress("col_macaddr", x => x.MacAddress)
	.MapDate("col_date", x => x.Date)
	.MapInterval("col_interval", x => x.TimeSpan)
	.MapNumeric("col_numeric", x => x.Numeric);

And then we can use it to efficiently store the data:

Synchronously:

private ulong WriteToDatabase(PostgreSQLCopyHelper<TestEntity> copyHelper, IEnumerable<TestEntity> entities)
{
    using (var connection = new NpgsqlConnection("Server=127.0.0.1;Port=5432;Database=sampledb;User Id=philipp;Password=test_pwd;"))
    {
        connection.Open();

        // Returns count of rows written 
        return copyHelper.SaveAll(connection, entities);
    }
}

Or asynchronously:

private async Task<ulong> WriteToDatabaseAsync(PostgreSQLCopyHelper<TestEntity> copyHelper, IEnumerable<TestEntity> entities, CancellationToken cancellationToken = default)
{
    using (var connection = new NpgsqlConnection("Server=127.0.0.1;Port=5432;Database=sampledb;User Id=philipp;Password=test_pwd;"))
    {
        await connection.OpenAsync(cancellationToken);

        // Returns count of rows written 
        return await copyHelper.SaveAllAsync(connection, entities, cancellationToken);
    }
}

Or asynchronously with asynchronous enumerables:

private async Task<ulong> WriteToDatabaseAsync(PostgreSQLCopyHelper<TestEntity> copyHelper, IAsyncEnumerable<TestEntity> entities, CancellationToken cancellationToken = default)
{
    using (var connection = new NpgsqlConnection("Server=127.0.0.1;Port=5432;Database=sampledb;User Id=philipp;Password=test_pwd;"))
    {
        await connection.OpenAsync(cancellationToken);

        // Returns count of rows written 
        return await copyHelper.SaveAllAsync(connection, entities, cancellationToken);
    }
}

PostgreSQLCopyHelper Custom Type Maps

One can always define a custom map function for any property to any Npgsql type.

For example:

.Map("geo", x => x.geo, NpgsqlDbType.Point)

Mapping Composite Types

Imagine you have a composite type called person_type in a schema of your database:

create type sample.person_type as
(
    first_name text,
    last_name text,
    birth_date date
);

And it is used in a table called CompositeTest:

create table sample.CompositeTest
(
    col_text text,
    col_person sample.person_type                
)

You first need to map the Postgres person_type to a C# class:

private class PersonType
{
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public DateTime BirthDate { get; set; }
}

A hint: Npgsql always converts the property name to a snake case column name, so FirstName is mapped to first_name by convention. You can use the [PgName] attribute to explicitly set the Postgres type name.

Next the table is mapped to the following C# model:

private class SampleEntity
{
    public string TextColumn { get; set; }

    public PersonType CompositeTypeColumn { get; set; }
}

And now we can bulk write SampleEntity instances using PostgreSQLCopyHelper like this:

connection.TypeMapper.MapComposite<PersonType>("sample.person_type");

// ... alternatively you can set it globally at any place in your application using the NpgsqlConnection.GlobalTypeMapper:
//
// NpgsqlConnection.GlobalTypeMapper.MapComposite<PersonType>("sample.person_type");

var subject = new PostgreSQLCopyHelper<SampleEntity>("sample", "CompositeTest")
         .MapText("col_text", x => x.TextColumn)
         .Map("col_person", x => x.CompositeTypeColumn);

var entities = new List<SampleEntity>();

entities.Add(new SampleEntity
{
    TextColumn = "0",
    CompositeTypeColumn = new PersonType { FirstName = "Fake", LastName = "Fakerton", BirthDate = new DateTime(1987, 1, 11) }
});

entities.Add(new SampleEntity
{
    TextColumn = "1",
    CompositeTypeColumn = new PersonType { FirstName = "Philipp", LastName = "Wagner", BirthDate = new DateTime(1912, 1, 11) }
});

subject.SaveAll(connection, entities);

In the listing you see, that we need to tell Npgsql how to map the Postgres type using MapComposite<>. This can be done per Connection like this:

connection.TypeMapper.MapComposite<PersonType>("sample.person_type");

Or you can alternatively set the Mapping globally at any place in your application using the NpgsqlConnection.GlobalTypeMapper:

NpgsqlConnection.GlobalTypeMapper.MapComposite<PersonType>("sample.person_type");

PostgreSQLCopyHelper.NodaTime: NodaTime Support

The PostgreSQLCopyHelper.NodaTime package extends PostgreSQLCopyHelper for NodaTime types.

To install PostgreSQLCopyHelper.NodaTime, run the following command in the Package Manager Console:

PM> Install-Package PostgreSQLCopyHelper

It uses the Npgsql.NodaTime plugin, which needs to be enabled by running:

using Npgsql;

// Place this at the beginning of your program to use NodaTime everywhere (recommended)
NpgsqlConnection.GlobalTypeMapper.UseNodaTime();

// Or to temporarily use NodaTime on a single connection only:
conn.TypeMapper.UseNodaTime();

For more details see the Npgsql documentation for NodaTime.

Case-Sensitive Identifiers

By default the library does not apply quotes to identifiers, such as Table Names and Column Names. If you want PostgreSQL-conform quoting for identifiers, then use the UsePostgresQuoting method like this:

var copyHelper = new PostgreSQLCopyHelper<MixedCaseEntity>("sample", "MixedCaseEntity")
                     .UsePostgresQuoting()
                     .MapInteger("Property_One", x => x.Property_One)
                     .MapText("Property_Two", x => x.Property_Two);

License

PostgreSQLCopyHelper is licensed under the MIT License. See LICENSE for details.

Copyright (c) Philipp Wagner, Steven Yeh and Contributors

postgresqlcopyhelper's People

Contributors

adamdriscoll avatar bytefish avatar cooksauce avatar marklahn avatar mikkelbu avatar say25 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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

postgresqlcopyhelper's Issues

make columns available as protected or public property

I have started using your package for the following scenario

  1. Create Temp Table
  2. Copy into table
  3. Use Update SQL to overlay

I realized after I set up the CopyHelper, I could use the Column Meta data to dynamically
create the TempTable, but the property is private , so can't access

What I would like is to have that property made public or projected so I can access it.

Compatibility issue with Npgsql 4.0.11

Hello, I'm a bit confused on the dependencies. It seems that PostgreSQLCopyHelper 2.4.x should work with Npgsql 4.0.11 but I keep getting errors that it needs Npgsql 4.0.0. Due to other dependencies, our project requires Npgsql 4.0.11. Which version of PostgreSQLCopyHelper is compatible with this version?

Mapper for "Point" Datatype Column

Hi,
sc1
sc2

I am not sure if we have a method for mapping a Point Datatype DB column(eg. like .MapText or .MapTimeStamp). I was searching on the internet for solution of this issue. But didn't found anything which can help me. I was trying to send the value with .MapText in a column which has Point datatype in DB, but I am getting 22P03 error(incorrect binary data format) after execution of copyHelper.SaveAll method.

Can anyone help me on this topic that how I can map point datatype column with my c# class property while creating copyhelper object for BulkInsert.

Here are some screenshots of my C# Class (Please see highlighted text)

Incompatibility with Npgsql 4.0.4

First off, thank you for this helper!

We are using Npgsql 4.0.4 on our project along with this helper, but it seems like it's not compatible with our Npgsql version. We were able to make it work by downgrading it to 4.0.0, but we'd prefer not to.

Is there any way it could be updated to support 4.0.4?

Thank you!

Increase Version to 1.0

The library currently has Version 0.2, which makes it look like an early Beta release. The library is built on top of Npgsql and comes with a thorough Unit Test Suite. The version number should be updated to Version 1.0.

MapNullable?

Hey everyone, having an issue inserting in bulk when one of our values is null. We keep getting the "end of message" error. We're pretty confident that we've tracked it down to a single column that allows nulls. The column is mapped to a BigInt. If the value is null (which the database allows), it throws an exception. We also tried to set the value to DBNull.Value but since it's mapped to a BigInt, we can't do that either.

Any suggestions?

42601: syntax error at or near "#" during executing SaveAll(conn, entityList) method

Here are the details:

Entity.cs file

public class PickrrMIS
    {
        [Column("PickrrOrderID")]
        public string? PickrrOrderID { get; set; }

        [Column("WaybillType")]
        public string? WaybillType { get; set; }

        [Column("PICKRRTrackingID")]
        public string? PICKRRTrackingID { get; set; }

        [Column("ClientOrderID")]
        public string? ClientOrderID { get; set; }

        [Column("UserEmail")]
        public string? UserEmail { get; set; }

        [Column("PlacedDate")]
        public string? PlacedDate { get; set; }

        [Column("PickupDate")]
        public string? PickupDate { get; set; }

        [Column("ItemName")]
        public string? ItemName { get; set; }

        [Column("ItemQuantity")]
        public string? ItemQuantity { get; set; }

        [Column("Updatedlength")]
        public string? Updatedlength { get; set; }

        [Column("UpdatedBreadth")]
        public string? UpdatedBreadth { get; set; }

        [Column("UpdatedHeight")]
        public string? UpdatedHeight { get; set; }

        [Column("UpdatedDeadWeight")]
        public string? UpdatedDeadWeight { get; set; }

        [Column("Userlength")]
        public string? Userlength { get; set; }

        [Column("UserBreadth")]
        public string? UserBreadth { get; set; }

        [Column("UserHeight")]
        public string? UserHeight { get; set; }

        [Column("UserDeadWeight")]
        public string? UserDeadWeight { get; set; }

        [Column("ChargedWeight")]
        public string? ChargedWeight { get; set; }

        [Column("IsReverse")]
        public string? IsReverse { get; set; }

        [Column("OrderType")]
        public string? OrderType { get; set; }

        [Column("CODAmount")]
        public string? CODAmount { get; set; }

        [Column("InvoiceValue")]
        public string? InvoiceValue { get; set; }

        [Column("CourierUsed")]
        public string? CourierUsed { get; set; }

        [Column("DropCustomerName")]
        public string? DropCustomerName { get; set; }

        [Column("DropCustomerPhone")]
        public string? DropCustomerPhone { get; set; }

        [Column("DropPincode")]
        public string? DropPincode { get; set; }

        [Column("DropAddress")]
        public string? DropAddress { get; set; }

        [Column("DropCity")]
        public string? DropCity { get; set; }

        [Column("DropState")]
        public string? DropState { get; set; }

        [Column("PickupName")]
        public string? PickupName { get; set; }

        [Column("PickupPhoneNumber")]
        public string? PickupPhoneNumber { get; set; }

        [Column("PickupPincode")]
        public string? PickupPincode { get; set; }

        [Column("PickupAddress")]
        public string? PickupAddress { get; set; }

        [Column("ReceivedBy")]
        public string? ReceivedBy { get; set; }

        [Column("CurrentStatus")]
        public string? CurrentStatus { get; set; }

        [Column("CurrentStatusUpdate")]
        public string? CurrentStatusUpdate { get; set; }

        [Column("CurrentStatusDatetime")]
        public string? CurrentStatusDatetime { get; set; }

        [Column("OutForDeliveryCount")]
        public string? OutForDeliveryCount { get; set; }

        [Column("Latesttrackinfo")]
        public string? Latesttrackinfo { get; set; }

        [Column("LatestLocation")]
        public string? LatestLocation { get; set; }

        [Column("FirstAttemptDate")]
        public string? FirstAttemptDate { get; set; }

        [Column("LatestNDRRemark")]
        public string? LatestNDRRemark { get; set; }

        [Column("LatestNDRDate")]
        public string? LatestNDRDate { get; set; }

        [Column("OrderZone")]
        public string? OrderZone { get; set; }

        [Column("EDDDate")]
        public string? EDDDate { get; set; }

        [Column("DestinationEmail")]
        public string? DestinationEmail { get; set; }

        [Column("#TrackingId")]
        public string? NumTrackingId { get; set; }

        [Column("LineItems")]
        public string? LineItems { get; set; }

        [Column("RTOWaybill")]
        public string? RTOWaybill { get; set; }

        [Column("SKUName")]
        public string? SKUName { get; set; }

        [Column("SKUQuantity")]
        public string? SKUQuantity { get; set; }

        [Column("SKUUnitPrice")]
        public string? SKUUnitPrice { get; set; }

        [Column("SKUCode")]
        public string? SKUCode { get; set; }

        [Column("otp")]
        public string? otp { get; set; }

        [Column("is_otp_delivered")]
        public string? is_otp_delivered { get; set; }

        [Column("FirstNdrDate")]
        public string? FirstNdrDate { get; set; }

        [Column("FirstNdrReason")]
        public string? FirstNdrReason { get; set; }

        [Column("FirstNdrSubreason")]
        public string? FirstNdrSubreason { get; set; }

        [Column("FirstNdrStatusCode")]
        public string? FirstNdrStatusCode { get; set; }

        [Column("SecondNdrDate")]
        public string? SecondNdrDate { get; set; }

        [Column("SecondNdrReason")]
        public string? SecondNdrReason { get; set; }

        [Column("SecondNdrSubreason")]
        public string? SecondNdrSubreason { get; set; }

        [Column("SecondNdrStatusCode")]
        public string? SecondNdrStatusCode { get; set; }

        [Column("ThirdNdrDate")]
        public string? ThirdNdrDate { get; set; }

        [Column("ThirdNdrReason")]
        public string? ThirdNdrReason { get; set; }

        [Column("ThirdNdrSubreason")]
        public string? ThirdNdrSubreason { get; set; }

        [Column("ThirdNdrStatusCode")]
        public string? ThirdNdrStatusCode { get; set; }

        [Column("LatestNdrStatusCode")]
        public string? LatestNdrStatusCode { get; set; }

        [Column("LatestNdrReason")]
        public string? LatestNdrReason { get; set; }

        [Column("RtoInitiatedDate")]
        public string? RtoInitiatedDate { get; set; }

        [Column("RtoReason")]
        public string? RtoReason { get; set; }

        [Column("RtdDate")]
        public string? RtdDate { get; set; }

        [Column("DeliveredDate")]
        public string? DeliveredDate { get; set; }

        [Column("IsReverseQC")]
        public string? IsReverseQC { get; set; }

        [Column("QCRejectionReason")]
        public string? QCRejectionReason { get; set; }

        [Column("ScheduledShipDate")]
        public string? ScheduledShipDate { get; set; }

        [Column("LostDate")]
        public string? LostDate { get; set; }

        [Column("LostLiabilityAmount")]
        public string? LostLiabilityAmount { get; set; }

        [Column("LiabilityPaidStatus")]
        public string? LiabilityPaidStatus { get; set; }

        [Column("LiabilityClaimSettlementDate")]
        public string? LiabilityClaimSettlementDate { get; set; }

    }

Mapping Data:

PostgreSQLCopyHelper<PickrrMIS> copyHelper = new PostgreSQLCopyHelper<PickrrMIS>("public", "pickrrmis")
                                                           .MapText("PickrrOrderID", x => x.PickrrOrderID)
                                                           .MapText("WaybillType", x => x.WaybillType)
                                                           .MapText("PICKRRTrackingID", x => x.PICKRRTrackingID)
                                                           .MapText("ClientOrderID", x => x.ClientOrderID)
                                                           .MapText("UserEmail", x => x.UserEmail)
                                                           .MapText("PlacedDate", x => x.PlacedDate)
                                                           .MapText("PickupDate", x => x.PickupDate)
                                                           .MapText("ItemName", x => x.ItemName)
                                                           .MapText("ItemQuantity", x => x.ItemQuantity)
                                                           .MapText("Updatedlength", x => x.Updatedlength)
                                                           .MapText("UpdatedBreadth", x => x.UpdatedBreadth)
                                                           .MapText("UpdatedHeight", x => x.UpdatedHeight)
                                                           .MapText("UpdatedDeadWeight", x => x.UpdatedDeadWeight)
                                                           .MapText("Userlength", x => x.Userlength)
                                                           .MapText("UserBreadth", x => x.UserBreadth)
                                                           .MapText("UserHeight", x => x.UserHeight)
                                                           .MapText("UserDeadWeight", x => x.UserDeadWeight)
                                                           .MapText("ChargedWeight", x => x.ChargedWeight)
                                                           .MapText("IsReverse", x => x.IsReverse)
                                                           .MapText("OrderType", x => x.OrderType)
                                                           .MapText("CODAmount", x => x.CODAmount)
                                                           .MapText("InvoiceValue", x => x.InvoiceValue)
                                                           .MapText("CourierUsed", x => x.CourierUsed)
                                                           .MapText("DropCustomerName", x => x.DropCustomerName)
                                                           .MapText("DropCustomerPhone", x => x.DropCustomerPhone)
                                                           .MapText("DropPincode", x => x.DropPincode)
                                                           .MapText("DropAddress", x => x.DropAddress)
                                                           .MapText("DropCity", x => x.DropCity)
                                                           .MapText("DropState", x => x.DropState)
                                                           .MapText("PickupName", x => x.PickupName)
                                                           .MapText("PickupPhoneNumber", x => x.PickupPhoneNumber)
                                                           .MapText("PickupPincode", x => x.PickupPincode)
                                                           .MapText("PickupAddress", x => x.PickupAddress)
                                                           .MapText("ReceivedBy", x => x.ReceivedBy)
                                                           .MapText("CurrentStatus", x => x.CurrentStatus)
                                                           .MapText("CurrentStatusUpdate", x => x.CurrentStatusUpdate)
                                                           .MapText("CurrentStatusDatetime", x => x.CurrentStatusDatetime)
                                                           .MapText("OutForDeliveryCount", x => x.OutForDeliveryCount)
                                                           .MapText("Latesttrackinfo", x => x.Latesttrackinfo)
                                                           .MapText("LatestLocation", x => x.LatestLocation)
                                                           .MapText("FirstAttemptDate", x => x.FirstAttemptDate)
                                                           .MapText("LatestNDRRemark", x => x.LatestNDRRemark)
                                                           .MapText("LatestNDRDate", x => x.LatestNDRDate)
                                                           .MapText("OrderZone", x => x.OrderZone)
                                                           .MapText("EDDDate", x => x.EDDDate)
                                                           .MapText("DestinationEmail", x => x.DestinationEmail)
                                                           .MapText("#TrackingId", x => x.NumTrackingId)
                                                           .MapText("LineItems", x => x.LineItems)
                                                           .MapText("RTOWaybill", x => x.RTOWaybill)
                                                           .MapText("SKUName", x => x.SKUName)
                                                           .MapText("SKUQuantity", x => x.SKUQuantity)
                                                           .MapText("SKUUnitPrice", x => x.SKUUnitPrice)
                                                           .MapText("SKUCode", x => x.SKUCode)
                                                           .MapText("otp", x => x.otp)
                                                           .MapText("is_otp_delivered", x => x.is_otp_delivered)
                                                           .MapText("FirstNdrDate", x => x.FirstNdrDate)
                                                           .MapText("FirstNdrReason", x => x.FirstNdrReason)
                                                           .MapText("FirstNdrSubreason", x => x.FirstNdrSubreason)
                                                           .MapText("FirstNdrStatusCode", x => x.FirstNdrStatusCode)
                                                           .MapText("SecondNdrDate", x => x.SecondNdrDate)
                                                           .MapText("SecondNdrReason", x => x.SecondNdrReason)
                                                           .MapText("SecondNdrSubreason", x => x.SecondNdrSubreason)
                                                           .MapText("SecondNdrStatusCode", x => x.SecondNdrStatusCode)
                                                           .MapText("ThirdNdrDate", x => x.ThirdNdrDate)
                                                           .MapText("ThirdNdrReason", x => x.ThirdNdrReason)
                                                           .MapText("ThirdNdrSubreason", x => x.ThirdNdrSubreason)
                                                           .MapText("ThirdNdrStatusCode", x => x.ThirdNdrStatusCode)
                                                           .MapText("LatestNdrStatusCode", x => x.LatestNdrStatusCode)
                                                           .MapText("LatestNdrReason", x => x.LatestNdrReason)
                                                           .MapText("RtoInitiatedDate", x => x.RtoInitiatedDate)
                                                           .MapText("RtoReason", x => x.RtoReason)
                                                           .MapText("RtdDate", x => x.RtdDate)
                                                           .MapText("DeliveredDate", x => x.DeliveredDate)
                                                           .MapText("IsReverseQC", x => x.IsReverseQC)
                                                           .MapText("QCRejectionReason", x => x.QCRejectionReason)
                                                           .MapText("ScheduledShipDate", x => x.ScheduledShipDate)
                                                           .MapText("LostDate", x => x.LostDate)
                                                           .MapText("LostLiabilityAmount", x => x.LostLiabilityAmount)
                                                           .MapText("LiabilityPaidStatus", x => x.LiabilityPaidStatus)
                                                           .MapText("LiabilityClaimSettlementDate", x => x.LiabilityClaimSettlementDate);

Error Description:
42601: syntax error at or near "#"
POSITION: 694

at Npgsql.Internal.NpgsqlConnector.g__ReadMessageLong|221_0(NpgsqlConnector connector, Boolean async, DataRowLoadingMode dataRowLoadingMode, Boolean readingNotifications, Boolean isReadingPrependedMessage)
at Npgsql.NpgsqlBinaryImporter.Init(String copyFromCommand, Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlConnection.BeginBinaryImport(String copyFromCommand, Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlConnection.BeginBinaryImport(String copyFromCommand)
at PostgreSQLCopyHelper.PostgreSQLCopyHelper1.DoSaveAllAsync(NpgsqlConnection connection, IEnumerable1 entities, CancellationToken cancellationToken)
at PostgreSQLCopyHelper.PostgreSQLCopyHelper1.SaveAll(NpgsqlConnection connection, IEnumerable1 entities)
at Sevices.PostgresHandler.SaveData(DataTable datatable, NpgsqlConnection conn) in
C:\Codebase\PostgresHandler.cs:line 116

Expose Column info and GetCopyCommand publicly

It would be extremely helpful if private readonly List<ColumnDefinition> _columns;
was actually a public or at min protected property.

That would let me then use that metadata for things like dynamically creating a temp table

it would also be good if private string GetCopyCommand() was actually public, this would allow for eaiser debugging

Major version bump for Npgsql?

Is your feature request related to a problem? Please describe.
I am getting critical notices from our dependency monitor due to a remote code execution vulnerability in System.Text.Encodings.Web that comes in via [email protected]. Npgsql is now on version 5.0.10, so maybe it's time to version bump this library?

Describe the solution you'd like
Next version of this library with version bumps of the dependencies.

Describe alternatives you've considered
Could fork the library and bump it myself but I'd rather benefit from maintenance efforts. I'd submit a PR but the testing in the repo is not transparent to me (dotnet test throws exceptions).

Additional context
None

copyHelper.SaveAll deadlocks

Description
It appears that I am getting a deadlock when calling copyHelper.SaveAll(connection, tableEntities);. The same data inserts without a problem when I use an INSERT command. The SaveAll deadlocks whether I'm attempting to insert 1 or a million records. It even deadlocks when I attempt to SaveAll with an empty collection of tableEntities.

Environment
Windows 10 Enterprise
.NET 4.8
PostgreSQL 12
WPF application
C#

To Reproduce
My copyHelper looks like this:

            var copyHelper = new PostgreSQLCopyHelper<TableEntity>("MY_TABLE")
                .UsePostgresQuoting(true)
                .MapUUID("HARVEST_ID", x => x.HarvestGuid)
                .MapVarchar("OWNER", x => x.Owner)
                .MapVarchar("NAME", x => x.Name);

TableEntity is simply this:

    public class TableEntity
    {
        public Guid HarvestGuid { get; set; }
        public string Owner { get; set; }
        public string Name { get; set; }
    }

and tableEntities is:

            List<TableEntity> tableEntities = new List<TableEntity>();

To insert the records, the following code is executed:

        public bool InsertTables(Guid harvestGuid, DataTable dt)
        {
            if (!DataStoreReady)
                return false;

            if (dt == null || dt.Rows.Count == 0)
                return true;

            // prepare the data for insertion.
            var copyHelper = new PostgreSQLCopyHelper<TableEntity>("MY_TABLE")
                .UsePostgresQuoting(true)
                .MapUUID("HARVEST_ID", x => x.HarvestGuid)
                .MapVarchar("OWNER", x => x.Owner)
                .MapVarchar("NAME", x => x.Name);
                
            List<TableEntity> tableEntities = new List<TableEntity>();

            //brute force...
            foreach(DataRow row in dt.Rows)
            {
                TableEntity t = new TableEntity();

                t.HarvestGuid = harvestGuid;
                t.Owner = row["OWNER"].ToString();
                t.Name = row["TABLE_NAME"].ToString();

                tableEntities.Add(t);
            }

            try
            {

                using (NpgsqlConnection conn = new NpgsqlConnection(_connectionString.ConnectionString))
                {
                    conn.Open();

                    Logger.Debug("Beginning insertion of TABLE records.");

                    copyHelper.SaveAll(conn, tableEntities);  // <-- here is where the code deadlocks.

                    Logger.Debug("Completed insertion of TABLE records.");

                }
                return true;
            }
            catch (Exception ex)
            {
                Logger.Error("An exception was thrown while attempting to insert harvest inforamtion.");
                Logger.Error(ex);
                return false;
            }
        }

Expected behavior
I expect the records to be inserted into the table.

Desktop (please complete the following information):
Windows 10 Enterprise

Additional context
I've tried this with 10,000 records, 1 record, even 0 records in the tableEntities list, but it always locks up. No exception is thrown. This is all executing on the UI thread.

Does this support DotNetFramework 4.6.2

Hi Team,
We are using Dot net framework 4.6.2 version, came across this library, in the readme file it is given as .NetFramework Core version,

wanted to know does, this support Dot net framework 4.6.2 version also?

We are using NHibernate ORM tool and PostrgreSQL database

Struggling to Import Empty DateTime

hi,
thank you for this brilliant tools!!!
only one problem: import doesn't work for weatherData-record where column "date" is empty: no record will be created also no error-message ...
thanks for your support!

Add Support for .NET Core

.NET Core 1.0 has been released by Microsoft. PostgreSQLCopyHelper should be updated to support .NET Core. TinyCsvParser has already been updated to .NET Core, so it can be used as a template.

Update README for async methods

The README currently only shows the synchronous methods. This could give the false impression, that the library doesn't support async methods. We should add a section on how to use the asynchronous SaveAllAsync.

Bulk Insert with auto increment unique primary key

Hi,

I am using PostgreSQLCopyHelper library in our project for creating bulk data. I want to insert bulk data in a table which contains Primary key. I am getting the "23505: duplicate key value violates unique constraint" error when PostgreSQLCopyHelper.SaveAll() is executed in the code.

Table Structure:

`TABLE empty_permission_details`
`(`
    id bigint NOT NULL DEFAULT nextval('"empty_permission_details_Id_seq"'::regclass),
    container_number character varying(11) COLLATE pg_catalog."default" NOT NULL,
    remarks character varying(350) COLLATE pg_catalog."default",
    CONSTRAINT "PK_empty_permission_details" PRIMARY KEY ("id")
`)`

Model Class:-

public class EmptyPermissionDetail
{
        [Key]
        public long Id { get; set; }
	public string Container_Number { get; set; }
	public string Remarks { get; set; }
}

Already populate a list of EmptyPermissionDetail where Id is 0. I want to pass the populated list
In the "SaveAll()" paramete where unique Id will be auto generated.

does it support composite types?

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Add any other context or screenshots about the feature request here.

How to insert in to multiple tables and maintain foreign keys

Hi Team,

Thanks for this library, it really helped me in loading bulk data. I have a question here,

We have to load the data in to 2 tables.

Table 1: context
In context table details id is referenced

Table 2 : Details
In the Details table context id from the above is referenced

In the UI for the user based on the keys we are showing the data. In this case I am able to insert data to context. I want the context id to be inserted in to details table and vice-versa, this process should be completed side by side, as soon as the load completes user want to see the data on the screen.

Please help me out here or provide some suggestions on how to achieve this using this helper class, as this class loads the data very fast and want to use this to achieve the above task

Thanks in advance.

Async Support

Hi!

When will you provide an async/await support to this great lib?

Thanks!

42601: syntax error at or near ")" when trying to make SaveAll()

Greetings. I've got an entity Product:

public class Product
{
   public int Id { get; set; }
   public int TimeRef { get; set; }
   public string AccountType { get; set; }
   public string Code { get; set; }
   public string CountryCode { get; set; }
   public string Type { get; set; }
   public decimal? Value { get; set; }
   public string Status { get; set; }
}

And I'm trying to execute this code:

var copyHelper = new PostgreSQLCopyHelper<Product>("Products");
wait using (var connection = new NpgsqlConnection("Host=localhost;Port=5432;Database=CopyTest;Username=postgres;Password=12345;"))
{
   await connection.OpenAsync();
   await copyHelper.SaveAllAsync(connection, new List<Product>{new Product
       {
            AccountType = "Exports", Code = "00", CountryCode = "UK",
            Status = "Pending", TimeRef = 123, Type = "Hey", Id = 123
       }});
 }

And I'm getting this:
image

Npgsql.PostgresException (0x80004005): 42601: syntax error at or near ")"
   at Npgsql.NpgsqlConnector.<ReadMessage>g__ReadMessageLong|194_0(NpgsqlConnector connector, Boolean async, DataRowLoadingMode dataRowLoadingMode, Boolean readingNotifications, Boolean isReadingPrependedMessage)
   at Npgsql.NpgsqlBinaryImporter..ctor(NpgsqlConnector connector, String copyFromCommand)
   at Npgsql.NpgsqlConnection.BeginBinaryImport(String copyFromCommand)
   at PostgreSQLCopyHelper.PostgreSQLCopyHelper`1.DoSaveAllAsync(NpgsqlConnection connection, IEnumerable`1 entities, CancellationToken cancellationToken)
   at copyTest.Controllers.CsvController.ImportCsv(IFormFile file) in C:\Users\petya\source\repos\copyTest\copyTest\Controllers\CsvController.cs:line 59
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
  Exception data:
    Severity: ERROR
    SqlState: 42601
    MessageText: syntax error at or near ")"
    Position: 15
    File: scan.l
    Line: 1149
    Routine: scanner_yyerror

I'm using EF Core to generate migrations. Database exists, table "Products" exists. I don't quite understand what I've done wrong. When I'm connecting connection.FullState changes to Open, so the problem is not in connection string.

Packages I'm using:
image

Could you help me, please?

Nullables Still Acting Up

Try to run copyHelper.SaveAll(connection, entities);

Where entities is a list of Student Objects with a string Name field and nullable int field for age.

If the first student in the entities list has a null age and the second has an age defined, it freaks out and fails.

Make PostgreSQLCopyHelper play nice with NodaTime

Hi!

Thanks for this library, and for all your efforts to make it work!

Right now, I'm trying to save a lot of data to the database using PostgreSQLCopyHelper, but I already use NodaTime globally in my application but when I call the method to save the information I'm getting the following error:

  • Using DateTime property = "Can't write CLR type System.DateTime to database type timestamp"

So, how can I use NodaTime LocalDateTime property and save it successfully on the database?

The number of affected rows is not captured/exposed when a COPY completes in PostgreSQLCopyHelper.SaveAll

Description of bug

In short, I ran into a rare bug where PostgreSQLCopyHelper would appear to copy rows but inserted 0 rows and did not throw an exception, in the PostgreSQLCopyHelper.SaveAll() method.

See npgsql/npgsql#2112.

In debugging the issue, I realized it would be necessary to expose the number of rows inserted to the methods in PostgreSQLCopyHelper.SaveAll() and NpgsqlBinaryImporter.Complete().
(Then at some point the issue went away - so I can't reproduce the original bug unfortunately. It might have been an issue with a slightly older Postgresql before I upgraded it.)

Proposed enhancement

I am submitting Pull requests to implement the "number of rows copied" enhancement to both @npgsql npgsql/npgsql and PostgreSQLCopyHelper.

The PostgreSQLCopyHelper pull request updates PostgreSQLCopyHelper.SaveAll() to return int.

This enhancement to PostgreSQLCopyHelper depends on npgsql integrating my related enhancement pull request, because npgsql currently omits the COPY row count it receives from Postgresql.
(I will post the relevant npgsql and PostgreSQLCopyHelper pull requests soon.)

Motivation - why this is important to me

Putting aside the rare silent failure copy bug, this feature is still important to my projects, because I want to be able to verify the count of rows inserted by COPY, and Postgresql exposes this information, but Npgsql and PostgreSQLCopyHelper currently do not.

Error when insert bytea[] values

I couldn't insert byte[] values. Occurs error "08P01: not enough data left in message" when i call method copyHelper.SaveAll(connection, entities). Please, help!

DateTimeOffset for TimeStamp

Great Tool! Hoping that you might be able to add a MapTimeStamp option for DateTimeOffset? Getting around it by converting things but it would be a great add. Thanks!!

Expose table and column definitions from the copyHelper

Is your feature request related to a problem? Please describe.
In my catch blocks, I would like to report information that is contained within the copyHelper - specifically, the table definition. Is there a reason why the table and column definitions that are passed into the copyHelper during construction cannot be exposed (read-only even)?

Describe the solution you'd like
I would like to be able to write code like this:

...
catch(Exception ex)
{
    Logger.Error($"An exception was thrown during bulk insertion into table {copyHelper.TableDefinition}.  Error: {ex.Message}");
}

Describe alternatives you've considered
As an alternative, I would have to keep track of the table and column definitions passed into the copyHelper in a separate construct and pass that along with the copyHelper into my methods that the copyHelper gets passed into. It would be much easier if the copyHelper just exposed the configuration information that was passed into it.

Additional context
I see that the TableDefinition class already exposes everything that I would want about the table definition. I would request though that the ToString() override simply output the fully qualified name of the table definition.

Thanks!

Error happens when work with net4.6

I have build my project with net4.6 and when I have used your SaveAll() function the exception has been thrown "Could not load file or assembly 'Npgsql, Version=3.1.0.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)"

I use npgsql 3.1.5. And it is works fine with you package under .netcore (!)

Could you fix this issue, please?

Bulk Update

Hi,

I found this morning your github project and working for bulk insert and very fast good job!

But, i want to bulk update, I may not have seen this repo maybe.

And Do you have a work on this ?

Than You For Repo !

Bug in Adding Quoted Identifier Support

On PostgreSQLCopyHelper 2.2.0 This works fine

new PostgreSQLCopyHelper<MyObject>("schema_name", "MyTable").

On PostgreSQLCopyHelper 2.3.1 I get this error:
relation "schema_name.MyTable" does not exist.

I would guess its in this diff somewhere:
5fd0682...master

column has null throwing the error

Describe the bug
column has null throwing the error

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error:invalid input syntax for type bigint:

Expected behavior
A clear and concise description of what you expected to happen.

Desktop (please complete the following information):

  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

Update Npgsql to 3.2.6

There are some problems with Package dependencies when using PostgreSQLCopyHelper in a netstandard 2.0 project. @beercsaba told me, that this doesn't happen with Npgsql 3.2.6. So Npgsql should be updated to Version 3.2.6.

Varchar(1) mapping

I am mapping my table columns on PostgreSQLCopyHelper, some of my table has varchar(1) datatype which is throwing error "22001: value too long for type character varying(1)", I am mapping text on this field.

PostgreSQLCopyHelper version 1.1.0
npgsql 3.0.8

PostgreSQLCopyHelper.SaveAll() makes recursive mapping when called and results in DB error

Hi,

I am using PostgreSQLCopyHelper library in our project (suite of applications) for daily data load functionality. We receive the bulk data from clients and it needs to be loaded into the PostgreSQL database for business operations. I have implemented the code changes as per the details given in README.md file. The code changes are working fine for some of the applications and loading the bulk data as expected. However, for few of the applications, I am getting the "23505: duplicate key value violates unique constraint" error when PostgreSQLCopyHelper.SaveAll() is executed in the code. The target database table where the data is loaded has a PRIMARY KEY constraint on one of the field and it should be UNIQUE and NOT NULL also. Please find below the details of the database table and code changes.

Database Table Structure:-

TABLE dbo.rpt_barcode
(
    claimid integer NOT NULL,
    db2key integer NOT NULL,
    dateprocessedatcps timestamp(0) without time zone NOT NULL,
    barcode character varying(50) COLLATE pg_catalog."default" NOT NULL,
    CONSTRAINT pk_rpt_barcode PRIMARY KEY (claimid)
)

Data Model Class:-

public class RptBarCode
{
	public int ClaimId { get; set; }
	public int Db2Key { get; set; }
	public DateTime DateProcessedAtCps { get; set; }
	public string BarCode { get; set; }
}

Data Load Code:-

private void WriteDataToServer()
{
		//Check if the DataTable has rows
		if (_tblBarCode.Rows.Count > 0)
		{
				//Serialize the DataTable into data entities
				List<RptBarCode> lstRptBarCodes = new List<RptBarCode>();
				lstRptBarCodes = (from DataRow rowRptBarCodeInfo in _tblBarCode.Rows
								select new RptBarCode()
								{
										ClaimId = (int)rowRptBarCodeInfo["ClaimId"],
										Db2Key = (int)rowRptBarCodeInfo["Db2Key"],
										DateProcessedAtCps = (DateTime)rowRptBarCodeInfo["DateProcessedAtCps"],
										BarCode = (string)rowRptBarCodeInfo["BarCode"]
								}).ToList<RptBarCode>();

		//Get the first data entity from list
		RptBarCode objRptBarCodeInfo = lstRptBarCodes.First<RptBarCode>();

		//Format the SchemaName for PostgreSQLCopyHelper config
		string schemaName = _barcodeTable.Trim().ToLower().Contains("dbo.") ? string.Empty : "dbo";

		//Define the PostgreSQLCopyHelper and map the rpt_barcode table fields
		PostgreSQLCopyHelper<RptBarCode> dataCopyHelper = new PostgreSQLCopyHelper<RptBarCode>(schemaName, _barcodeTable)
															.MapInteger("claimid", x => objRptBarCodeInfo.ClaimId)
															.MapInteger("db2key", x => objRptBarCodeInfo.Db2Key)
															.MapTimeStamp("dateprocessedatcps", x => objRptBarCodeInfo.DateProcessedAtCps)
															.MapVarchar("barcode", x => objRptBarCodeInfo.BarCode);

		//Save the data entities to PostgreSQL database
		dataCopyHelper.SaveAll(_connection, lstRptBarCodes);
	}
}

When "dataCopyHelper.SaveAll()" code is executed, it results in exception with error message, {"23505: duplicate key value violates unique constraint "pk_rpt_barcode"". I have debugged the code and observed that, after "dataCopyHelper.SaveAll()" is executed, the program control goes back to "PostgreSQLCopyHelper dataCopyHelper = new PostgreSQLCopyHelper(schemaName, _barcodeTable)" code and it again tries to map the same data set and save it to database. Since the same data set is already loaded to database, the next time load will result in duplicate key value violates error. The same code is implemented in other data load applications in the project and it works fine. I am not understanding as why the "dataCopyHelper.SaveAll()" code sends the program control back to the previous line and results in error.

Please check the issue and let me know if I am missing anything with the above code changes implementation. Thank you in advance.

Unable to install package from nuget

-Package : Unable to load the service index for source http://api.nuget.org/v3/index.json.
At line:1 char:16

  • Install-Package <<<< PostgreSQLCopyHelper
    • CategoryInfo : NotSpecified: (:) [Install-Package], Exception
    • FullyQualifiedErrorId : NuGetCmdletUnhandledException,NuGet.PackageManagement.PowerShellCmdlets.InstallPackageCommand

Error Npgsql.PostgresException: '22P03: incorrect binary data format'

I want to map class Rooster through the copyHelper mapping into the 'rooster' table.
See below for definitions.
I get the following error: 'Error Npgsql.PostgresException: '22P03: incorrect binary data format'

I suspect that one of the datatype mappings is not valid.

Begindatum_rooster is a DateTime with datetimekind UTC and to accomodate that I mapped to MapTimeStampTz.
After fixing the error for this datatype I got the new formentioned error.
Is it the float4? Should I use float8 in the database? Or do I need to map to datatype real?

Any hints are welcome.
Thanks in advance.

   public class Rooster 
    {
        public string Medewerker { get; set; }
        public int? Koppeling_rooster { get; set; }
        public DateTime? Begindatum_rooster { get; set; }
        public DateTime? Einddatum_rooster { get; set; }
        public float? Aantal_dagen_per_week { get; set; }
        public float? Aantal_uren_per_week { get; set; }
        public float? Aantal_FTE { get; set; }
        public float? Parttime____ { get; set; }
        public string PersoonsID { get; set; }
        public string Begindatum { get; set; }
        public float? FTE_Maandag { get; set; }
        public float? FTE_Dinsdag { get; set; }
        public float? FTE_Woensdag { get; set; }
        public float? FTE_Donderdag { get; set; }
        public float? FTE_Vrijdag { get; set; }

    }
var copyHelper = new PostgreSQLCopyHelper<Rooster>("public", tableName)
            .MapVarchar("Medewerker", x => x.Medewerker)
            .MapInteger("Koppeling_rooster", x => x.Koppeling_rooster)
            .MapTimeStampTz("Begindatum_rooster", x => x.Begindatum_rooster)
            .MapTimeStampTz("Einddatum_rooster", x => x.Einddatum_rooster)
            .MapDouble("Aantal_dagen_per_week", x => x.Aantal_dagen_per_week)
            .MapDouble("Aantal_uren_per_week", x => x.Aantal_uren_per_week)
            .MapDouble("Aantal_FTE", x => x.Aantal_FTE)
            .MapDouble("Parttime____", x => x.Parttime____)
            .MapVarchar("PersoonsID", x => x.PersoonsID)
            .MapVarchar("Begindatum", x => x.Begindatum)
            .MapDouble("FTE_Maandag", x => x.FTE_Maandag)
            .MapDouble("FTE_Dinsdag", x => x.FTE_Dinsdag)
            .MapDouble("FTE_Woensdag", x => x.FTE_Woensdag)
            .MapDouble("FTE_Donderdag", x => x.FTE_Donderdag)
            .MapDouble("FTE_Vrijdag", x => x.FTE_Vrijdag);
CREATE TABLE public.rooster (
	"Medewerker" varchar NULL,
	"Koppeling_rooster" int4 NULL,
	"Begindatum_rooster" timestamptz NULL,
	"Einddatum_rooster" timestamptz NULL,
	"Aantal_dagen_per_week" float4 NULL,
	"Aantal_uren_per_week" float4 NULL,
	"Aantal_FTE" float4 NULL,
	"Parttime____" float4 NULL,
	"PersoonsID" varchar NULL,
	"Begindatum" varchar NULL,
	"FTE_Maandag" float4 NULL,
	"FTE_Dinsdag" float4 NULL,
	"FTE_Woensdag" float4 NULL,
	"FTE_Donderdag" float4 NULL,
	"FTE_Vrijdag" float4 NULL
);

Return ids

Hi! Is there a way to return Ids after SaveAll?

Character Mapper Takes String

public static PostgreSQLCopyHelper<TEntity> MapCharacter<TEntity>(this PostgreSQLCopyHelper<TEntity> helper, string columnName, Func<TEntity, String> propertyGetter)
{
return helper.Map(columnName, propertyGetter, NpgsqlDbType.Char);
}

I noticed this code and thought it should rather take a Char instead of a String type. Is this intentional? Am I missing something?

Array of strings

Hi,
First of all, thanks for this nice piece of code, great work!
I was wondering if it is possible in any way to add arrays of string with PostgreSQLCopyHelper?
I see there is a .MapArray() which handles several types but not strings?
Cheers
Flo

Marking Releases

As a consumer of this library, it is hard to determine where and when changes were made.

Is it possible to:

  • Tag Releases
  • Add Release Notes to said tagged releases
  • Add a ReleaseNotes.MD containing a history of changes

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.