Skip to content

KeyAttribute malfunctioning when used along with CsvHelper #745

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
kwon0408 opened this issue Apr 16, 2025 · 1 comment
Open

KeyAttribute malfunctioning when used along with CsvHelper #745

kwon0408 opened this issue Apr 16, 2025 · 1 comment

Comments

@kwon0408
Copy link

I have used SqlKata's [Key] attribute without the name specified for years without any errors complaining about it, even with SqlKata.Execution.

However CsvHelper seems to be not happy with these nameless keys.

using CsvHelper;
using CsvHelper.Configuration;
using System.Globalization;

MyRecord[] records =
[
    new() { Id = 1, Value = "A" },
    new() { Id = 2, Value = "B" },
];

var csv = WriteCsv(records);
Console.WriteLine(csv);

static string WriteCsv<T>(IEnumerable<T> values)
{
    using var writer = new StringWriter();
    var config = new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        MemberTypes = MemberTypes.Properties | MemberTypes.Fields
    };
    using var csv = new CsvWriter(writer, config);

    csv.WriteRecords(values);
    return writer.ToString();
}

struct MyRecord
{
    [SqlKata.Key] // Error! 
    // [SqlKata.Key(nameof(Id))] or any other value for `name` is REQUIRED, when using with CsvHelper
    public int Id;

    public string Value;
}

The problem occurs when [Key] is used without Name (which defaults to ""). If the code above is executed, an exception is thrown like:

Unhandled exception. CsvHelper.WriterException: An unexpected error occurred. See inner exception for details.
IWriter state:
   Row: 1
   Index: 0
   HeaderRecord:
1

 ---> System.ArgumentNullException: Value cannot be null. (Parameter 'name')
   at SqlKata.ColumnAttribute..ctor(String name)
   at SqlKata.KeyAttribute..ctor(String name)
   at System.Reflection.CustomAttribute._CreateCaObject(RuntimeModule pModule, RuntimeType type, IRuntimeMethodInfo pCtor, Byte** ppBlob, Byte* pEndBlob, Int32* pcNamedArgs)
   at System.Reflection.CustomAttribute.AddCustomAttributes(ListBuilder`1& attributes, RuntimeModule decoratedModule, Int32 decoratedMetadataToken, RuntimeType attributeFilterType, Boolean mustBeInheritable, ListBuilder`1 derivedAttributes)
   at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeModule decoratedModule, Int32 decoratedMetadataToken, Int32 pcaCount, RuntimeType attributeFilterType)
   at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeFieldInfo field, RuntimeType caType)
   at System.Attribute.GetCustomAttributes(MemberInfo element, Boolean inherit)
   at CsvHelper.Configuration.ClassMap.ApplyAttributes(MemberMap memberMap)
   at CsvHelper.Configuration.ClassMap.AutoMapMembers(ClassMap map, CsvContext context, LinkedList`1 mapParents, Int32 indexStart)
   at CsvHelper.Configuration.ClassMap.AutoMap(CsvContext context)
   at CsvHelper.CsvContext.AutoMap(Type type)
   at CsvHelper.CsvWriter.WriteHeader(Type type)
   at CsvHelper.CsvWriter.WriteHeaderFromType[T]()
   at CsvHelper.CsvWriter.WriteRecords[T](IEnumerable`1 records)
   --- End of inner exception stack trace ---
   at CsvHelper.CsvWriter.WriteRecords[T](IEnumerable`1 records)
   at Program.<<Main>$>g__WriteCsv|0_0[T](IEnumerable`1 values) in C:\Users\user\source\repos\sln1\proj1\Program.cs:line 26
   at Program.<Main>$(String[] args) in C:\Users\user\source\repos\sln1\proj1\Program.cs:line 13
@cemahseri
Copy link

The problem occurs when [Key] is used without Name (which defaults to "")

Yes but no. Pay attention to CallerMemberName attribute on name parameter;

public KeyAttribute([System.Runtime.CompilerServices.CallerMemberName] string name = "")

CallerMemberName attribute doesn't work with fields, So either convert your struct something like this;

struct MyRecord
{
    [SqlKata.Key]
    public int Id { get; set; }

    public string Value;
}

Or just pass nameof(Id) as parameter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants