Search code examples
c#.netsql-serversqlbulkcopyfastmember

Trying to map a .NET string[] to a FastMember object but it's erroring/not mapping


I'm trying to insert a list of file names into a simple Sql Server table.

I'm trying to leverage SqlBulkCopy and @markgravell's FastMember library, as suggested by other SO answers.

public async Task AddFileNamesAsync(string[] fileNames)
{
    fileNames.ShouldNotBeNull();

    using (var bulkCopy = new SqlBulkCopy(ConnectionString))
    {
        using (var reader = ObjectReader.Create(fileNames))
        {
            bulkCopy.DestinationTableName = "FileNames";
            bulkCopy.ColumnMappings.Add("value", "FileName");
            await bulkCopy.WriteToServerAsync(reader)
                          .ConfigureAwait(false);
        }
    }
}

CREATE TABLE [dbo].[FileNames](
[FileNameId] [int] IDENTITY(1,1) NOT NULL,
[FileName] [varchar](500) NOT NULL

So I feel like it's a mapping issue either with:

  • FastMember not able to map to some internal backing collection
  • The FastMember backing collection doesn't have the same name as the DB column so it can't map.

Solution

  • I have never used this Library before however reviewing the GitHub source code it it requires a property to query from the source. Now on a string there isn't a property value really all you have to use is the Length property. Using Length. Now this may be an issue with the FastMember library, where it creates a CallSite accessor function to capture the Property from the target object.

    Source here

    Now I have had a play and cannot get access to any property that will work. At first glance their is a Chars property being returned in the TypeAccessor results but this does not appear to work.

    My suggestion is not really an answer to the question but a way to make it work. If you created a type that had a Property of the string then you could effectively get around this.

    public async Task AddFileNamesAsync(string[] fileNames)
    {
        fileNames.ShouldNotBeNull();
    
        var list = fileNames.Select(f => new { value = f });
    
        using (var bulkCopy = new SqlBulkCopy(ConnectionString))
        {
            using (var reader = ObjectReader.Create(list))
            {
                bulkCopy.DestinationTableName = "FileNames";
                bulkCopy.ColumnMappings.Add("value", "FileName");
    
                try
                {
                    await bulkCopy.WriteToServerAsync(reader)
                                    .ConfigureAwait(false);
    
                }
                catch(Exception ex)
                {
    
                }
            }
        }
    }
    

    Now this will work as we generated a new type with a property of value which is each file name. Now the execution should work as expected. (Note the try..catch... was just for testing).