Skip to content

Bug: BulkInsert with mappings #668

@SpaceOgre

Description

@SpaceOgre

I might be misunderstanding something about BulkInsert with mappings so I would like to know how to do this scenario with RepoDb and BulkInsert :)

Following class to insert:

public abstract record Customer
{
	public int Id { get; init; }
	abstract public CustomerType CustomerTypeId { get; }
	public string CustomerNumber { get; init; }
}

public record PrivateCustomer : Customer
{
	public override CustomerType CustomerTypeId => CustomerType.Private;
	public string SocialSecurityNumber { get; init; }
	public string FirstName { get; init; }
	public string LastName { get; init; }
	public string ChangedBy { get; init; }
}

To table

CREATE TABLE dbo.PrivateCustomer
(
  [CustomerId] int NOT NULL FOREIGN KEY REFERENCES dbo.Customer(Id) PRIMARY KEY CLUSTERED
  , [SocialSecurityNumber] varchar(100) NULL
  , [FirstName] nvarchar(100) NULL
  , [LastName] nvarchar(100) NULL
  , [ChangedBy] nvarchar(100) NULL
  , [SysStartTime] datetime2 GENERATED ALWAYS AS ROW START HIDDEN NOT NULL
  , [SysEndTime] datetime2 GENERATED ALWAYS AS ROW END HIDDEN NOT NULL
  , PERIOD FOR SYSTEM_TIME (SysStartTime,SysEndTime))
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.PrivateCustomerHistory));

So the Id property in the base Customer class should be inserted into the CustomerId column in db.

I'm trying this:

var mappings = new List<BulkInsertMapItem>();
mappings.Add(new BulkInsertMapItem("Id", "CustomerId"));

var insertedRows2 = await connection.BulkInsertAsync(privateCustomers, mappings: mappings, transaction: transaction);

But I'm getting: There are no field(s) found for this operation.

I have look in the source code and this part looks a bit weird to me:

IEnumerable<Field> entityFields = type.IsDictionaryStringObject() ? GetDictionaryStringObjectFields(((entities != null) ? entities.FirstOrDefault() : null) as IDictionary<string, object>) : FieldCache.Get(type);
IEnumerable<Field> enumerable = dbFields?.Select((DbField dbField) => dbField.AsField());
_ = DateTime.UtcNow;
if (entityFields?.Any() ?? false)
{
	enumerable = enumerable.Where((Field e) => entityFields.Any((Field f) => string.Equals(f.Name, e.Name, StringComparison.OrdinalIgnoreCase)));
}

if (mappings == null)
{
	mappings = enumerable?.Select((Field f) => new BulkInsertMapItem((entityFields?.FirstOrDefault((Field ef) => string.Equals(ef.Name, f.Name, StringComparison.OrdinalIgnoreCase)))!.Name ?? f.Name, f.Name));
}
else
{
	enumerable = enumerable.Where((Field e) => mappings.Any((BulkInsertMapItem m) => string.Equals(m.SourceColumn, e.Name, StringComparison.OrdinalIgnoreCase)));
}

if (enumerable == null || !enumerable.Any())
{
	throw new MissingFieldException("There are no field(s) found for this operation.");
}

So the mapping is used after entityFields are checked against dbFields. In my case this means that the Id property is not in enumerable when the mapping is done.

I'm just missing what mappings are for? And if so is there some way for me to solve it without manually mapping using a DataTable for instance?

Edit:

I have tried with both 1.1.1 and 1.1.2-beta3

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdeployedFeature or bug is deployed at the current releasefixedThe bug, issue, incident has been fixed.priorityTop priority feature or things to dotodoThings to be done in the future

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions