แมปชื่อคอลัมน์ด้วยตนเองด้วยคุณสมบัติของคลาส


173

ฉันยังใหม่กับ Dapper micro ORM จนถึงตอนนี้ฉันสามารถใช้สำหรับสิ่งที่เกี่ยวกับ ORM อย่างง่าย แต่ฉันไม่สามารถแมปชื่อคอลัมน์ฐานข้อมูลกับคุณสมบัติคลาสได้

ตัวอย่างเช่นฉันมีตารางฐานข้อมูลต่อไปนี้:

Table Name: Person
person_id  int
first_name varchar(50)
last_name  varchar(50)

และฉันมีชั้นเรียนที่เรียกว่าบุคคล:

public class Person 
{
    public int PersonId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

โปรดทราบว่าชื่อคอลัมน์ของฉันในตารางนั้นแตกต่างจากชื่อคุณสมบัติของคลาสที่ฉันพยายามแมปข้อมูลที่ฉันได้รับจากผลลัพธ์การสืบค้น

var sql = @"select top 1 PersonId,FirstName,LastName from Person";
using (var conn = ConnectionFactory.GetConnection())
{
    var person = conn.Query<Person>(sql).ToList();
    return person;
}

รหัสด้านบนจะไม่ทำงานเนื่องจากชื่อคอลัมน์ไม่ตรงกับคุณสมบัติ (Person) ของวัตถุ ในสถานการณ์นี้มีอะไรที่ฉันสามารถทำได้ใน Dapper เพื่อแมปด้วยตนเอง (เช่นperson_id => PersonId) ชื่อคอลัมน์ที่มีคุณสมบัติของวัตถุ?


สำเนาซ้ำของDapper ที่
David McEleney

คำตอบ:


80

ใช้งานได้ดี:

var sql = @"select top 1 person_id PersonId, first_name FirstName, last_name LastName from Person";
using (var conn = ConnectionFactory.GetConnection())
{
    var person = conn.Query<Person>(sql).ToList();
    return person;
}

Dapper ไม่มีสิ่งอำนวยความสะดวกที่ช่วยให้คุณระบุแอตทริบิวต์คอลัมน์ฉันไม่ได้ต่อต้านการเพิ่มการสนับสนุนหากเราไม่ดึงการพึ่งพา


@ Sam Saffron มีวิธีใดบ้างที่ฉันสามารถระบุชื่อแทนตารางได้ ฉันมีชั้นเรียนชื่อประเทศ แต่ใน db ตารางมีชื่อที่ซับซ้อนมากเนื่องจากการประชุมการตั้งชื่อ archic
TheVillageIdiot

64
คอลัมน์ Attribue จะเป็นประโยชน์สำหรับการแมปผลลัพธ์ของกระบวนงานที่เก็บ
Ronnie Overby

2
แอตทริบิวต์ของคอลัมน์จะมีประโยชน์สำหรับการอำนวยความสะดวกในการเชื่อมต่อทางกายภาพและ / หรือความหมายสั้น ๆ ระหว่างโดเมนของคุณและรายละเอียดการใช้เครื่องมือที่คุณใช้เพื่อทำให้เป็นรูปธรรม ดังนั้นอย่าเพิ่มการสนับสนุนสำหรับสิ่งนี้ !!!! :)
Derek Greer

ฉันไม่เข้าใจว่าเพราะเหตุใดคอลัมน์จึงไม่ปรากฏเมื่อมีการเพิ่มตาราง ตัวอย่างนี้ทำงานกับส่วนแทรกการอัพเดตและ SP อย่างไร ฉันอยากจะดู columnattribe มันตายง่ายและจะทำให้ชีวิตง่ายมากในการโยกย้ายจากโซลูชันอื่น ๆ ที่ใช้สิ่งที่คล้ายกับ linq-sql ที่หมดอายุแล้ว
Vman

197

Dapper สนับสนุนคอลัมน์ที่กำหนดเองไปยังผู้ทำแผนที่ มันทำผ่านอินเตอร์เฟซITypeMap CustomPropertyTypeMapระดับให้บริการโดย Dapper ที่สามารถทำมากที่สุดของงานนี้ ตัวอย่างเช่น:

Dapper.SqlMapper.SetTypeMap(
    typeof(TModel),
    new CustomPropertyTypeMap(
        typeof(TModel),
        (type, columnName) =>
            type.GetProperties().FirstOrDefault(prop =>
                prop.GetCustomAttributes(false)
                    .OfType<ColumnAttribute>()
                    .Any(attr => attr.Name == columnName))));

และรูปแบบ:

public class TModel {
    [Column(Name="my_property")]
    public int MyProperty { get; set; }
}

เป็นสิ่งสำคัญที่จะต้องทราบว่าการใช้งาน CustomPropertyTypeMap นั้นต้องการคุณลักษณะที่มีอยู่และตรงกับหนึ่งในชื่อคอลัมน์มิฉะนั้นคุณสมบัติจะไม่ถูกแมป DefaultTypeMapระดับให้การทำงานที่ได้มาตรฐานและสามารถยกระดับการเปลี่ยนแปลงพฤติกรรมนี้:

public class FallbackTypeMapper : SqlMapper.ITypeMap
{
    private readonly IEnumerable<SqlMapper.ITypeMap> _mappers;

    public FallbackTypeMapper(IEnumerable<SqlMapper.ITypeMap> mappers)
    {
        _mappers = mappers;
    }

    public SqlMapper.IMemberMap GetMember(string columnName)
    {
        foreach (var mapper in _mappers)
        {
            try
            {
                var result = mapper.GetMember(columnName);
                if (result != null)
                {
                    return result;
                }
            }
            catch (NotImplementedException nix)
            {
            // the CustomPropertyTypeMap only supports a no-args
            // constructor and throws a not implemented exception.
            // to work around that, catch and ignore.
            }
        }
        return null;
    }
    // implement other interface methods similarly

    // required sometime after version 1.13 of dapper
    public ConstructorInfo FindExplicitConstructor()
    {
        return _mappers
            .Select(mapper => mapper.FindExplicitConstructor())
            .FirstOrDefault(result => result != null);
    }
}

และเมื่อใช้งานแล้วมันจะกลายเป็นเรื่องง่ายในการสร้างตัวสร้างชนิดตัวกำหนดเองที่จะใช้คุณลักษณะโดยอัตโนมัติหากมีอยู่ แต่จะกลับไปใช้ลักษณะการทำงานแบบมาตรฐาน:

public class ColumnAttributeTypeMapper<T> : FallbackTypeMapper
{
    public ColumnAttributeTypeMapper()
        : base(new SqlMapper.ITypeMap[]
            {
                new CustomPropertyTypeMap(
                   typeof(T),
                   (type, columnName) =>
                       type.GetProperties().FirstOrDefault(prop =>
                           prop.GetCustomAttributes(false)
                               .OfType<ColumnAttribute>()
                               .Any(attr => attr.Name == columnName)
                           )
                   ),
                new DefaultTypeMap(typeof(T))
            })
    {
    }
}

นั่นหมายความว่าขณะนี้เราสามารถสนับสนุนประเภทที่ต้องการแผนที่โดยใช้แอตทริบิวต์ได้อย่างง่ายดาย:

Dapper.SqlMapper.SetTypeMap(
    typeof(MyModel),
    new ColumnAttributeTypeMapper<MyModel>());

นี่คือสรุปสาระสำคัญการรหัสที่มาเต็ม


ฉันได้รับการดิ้นรนกับปัญหาเดียวกันนี้ ... และดูเหมือนว่าเส้นทางที่ฉันควรจะไป ... ฉันค่อนข้างสับสนว่ารหัสนี้จะถูกเรียกว่า "Dapper.SqlMapper.SetTypeMap (typeof (MyModel), ใหม่ ColumnAttributeTypeMapper <MyModel> ()); " stackoverflow.com/questions/14814972/…
Rohan Büchner

คุณจะต้องโทรหาหนึ่งครั้งก่อนที่จะทำการสอบถามใด ๆ คุณสามารถทำได้ในตัวสร้างแบบคงที่เช่นมันจะต้องถูกเรียกเพียงครั้งเดียว
Kaleb Pederson

7
แนะนำให้ทำให้นี่เป็นคำตอบอย่างเป็นทางการ - คุณสมบัติของ Dapper นี้มีประโยชน์อย่างยิ่ง
killthrush

3
โซลูชันการแม็พที่โพสต์โดย @Oliver ( stackoverflow.com/a/34856158/364568 ) ทำงานและต้องใช้รหัสน้อย
ริกา

4
ฉันชอบที่คำว่า "ง่าย ๆ " ถูกโยนทิ้งไปอย่างง่ายดาย: P
Jonathan B.

80

ในบางครั้งสิ่งต่อไปนี้ควรใช้งานได้:

Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true;

6
แม้ว่านี่จะไม่ใช่คำตอบสำหรับคำถาม "การแมปชื่อคอลัมน์ด้วยตนเองกับคุณสมบัติของชั้นเรียน" สำหรับฉันมันดีกว่าการแม็ปด้วยตนเอง (น่าเสียดายที่ PostgreSQL จะดีกว่าถ้าใช้ขีดล่างในชื่อคอลัมน์) โปรดอย่าลบตัวเลือก MatchNamesWithUnderscores ในเวอร์ชันถัดไป! ขอบคุณ!!!
victorvartan

5
@victorvartan ไม่มีแผนการลบMatchNamesWithUnderscoresตัวเลือก ที่ดีที่สุดถ้าเราปรับโครงสร้างการกำหนดค่า API ใหม่ฉันจะปล่อยให้MatchNamesWithUnderscoresสมาชิกเข้าที่ (ยังคงใช้งานได้ดี) และเพิ่ม[Obsolete]เครื่องหมายเพื่อชี้ผู้คนไปยัง API ใหม่
Marc Gravell

4
@ MarcGravell คำว่า "สำหรับบางเวลา" ที่จุดเริ่มต้นของคำตอบของคุณทำให้ฉันกังวลว่าคุณอาจลบมันในรุ่นอนาคตขอบคุณสำหรับการชี้แจง! และขอขอบคุณอย่างยิ่งสำหรับ Dapper ซึ่งเป็นไมโคร ORM ที่ยอดเยี่ยมที่ฉันเพิ่งเริ่มใช้สำหรับโครงการเล็ก ๆ พร้อมกับ Npgsql บน ASP.NET Core!
victorvartan

2
นี่เป็นคำตอบที่ง่ายที่สุด ฉันได้พบกองและกองงาน แต่ในที่สุดก็สะดุดกับนี้ คำตอบที่ดีที่สุด แต่โฆษณาน้อยที่สุดได้อย่างง่ายดาย
teaMonkeyFruit

29

นี่คือโซลูชันที่ไม่ต้องใช้แอตทริบิวต์ที่ช่วยให้คุณสามารถเก็บรหัสโครงสร้างพื้นฐานของ POCO ของคุณได้

นี่คือคลาสที่จัดการกับการแมป พจนานุกรมจะทำงานหากคุณแมปคอลัมน์ทั้งหมด แต่คลาสนี้ให้คุณระบุความแตกต่างได้ นอกจากนี้ยังมีการแม็พกลับเพื่อให้คุณสามารถรับฟิลด์จากคอลัมน์และคอลัมน์จากฟิลด์ซึ่งจะมีประโยชน์เมื่อทำสิ่งต่าง ๆ เช่นการสร้างคำสั่ง sql

public class ColumnMap
{
    private readonly Dictionary<string, string> forward = new Dictionary<string, string>();
    private readonly Dictionary<string, string> reverse = new Dictionary<string, string>();

    public void Add(string t1, string t2)
    {
        forward.Add(t1, t2);
        reverse.Add(t2, t1);
    }

    public string this[string index]
    {
        get
        {
            // Check for a custom column map.
            if (forward.ContainsKey(index))
                return forward[index];
            if (reverse.ContainsKey(index))
                return reverse[index];

            // If no custom mapping exists, return the value passed in.
            return index;
        }
    }
}

ตั้งค่าวัตถุ ColumnMap และบอก Dapper ให้ใช้การจับคู่

var columnMap = new ColumnMap();
columnMap.Add("Field1", "Column1");
columnMap.Add("Field2", "Column2");
columnMap.Add("Field3", "Column3");

SqlMapper.SetTypeMap(typeof (MyClass), new CustomPropertyTypeMap(typeof (MyClass), (type, columnName) => type.GetProperty(columnMap[columnName])));

นี่เป็นวิธีแก้ปัญหาที่ดีเมื่อคุณมีคุณสมบัติไม่ตรงกันใน POCO ของคุณกับสิ่งที่ฐานข้อมูลของคุณส่งคืนตัวอย่างเช่นขั้นตอนการจัดเก็บ
สนใจ

1
ฉันชอบความรัดกุมที่การใช้แอตทริบิวต์ให้ แต่แนวคิดในวิธีนี้สะอาดกว่า - ไม่จับคู่ POCO ของคุณกับรายละเอียดฐานข้อมูล
Bruno Brant

หากฉันเข้าใจ Dapper อย่างถูกต้องจะไม่มีวิธีการแทรก () เฉพาะวิธีดำเนินการ () ... วิธีการจับคู่นี้จะใช้การแทรกได้หรือไม่ หรืออัพเดต ขอบคุณ
UuDdLrLrSs

29

ฉันทำสิ่งต่อไปนี้โดยใช้ dynamic และ LINQ:

    var sql = @"select top 1 person_id, first_name, last_name from Person";
    using (var conn = ConnectionFactory.GetConnection())
    {
        List<Person> person = conn.Query<dynamic>(sql)
                                  .Select(item => new Person()
                                  {
                                      PersonId = item.person_id,
                                      FirstName = item.first_name,
                                      LastName = item.last_name
                                  }
                                  .ToList();

        return person;
    }

12

วิธีที่ง่ายที่สุดในการบรรลุเป้าหมายนี้คือเพียงใช้นามแฝงในคอลัมน์ในข้อความค้นหาของคุณ หากคอลัมน์ฐานข้อมูลของคุณPERSON_IDและวัตถุของIDคุณคือสิ่งที่คุณสามารถทำได้select PERSON_ID as Id ...ในแบบสอบถามของคุณและ Dapper จะรับมันได้ตามที่คาดไว้


12

ถ่ายจากการทดสอบ Dapperซึ่งปัจจุบันอยู่ใน Dapper 1.42

// custom mapping
var map = new CustomPropertyTypeMap(typeof(TypeWithMapping), 
                                    (type, columnName) => type.GetProperties().FirstOrDefault(prop => GetDescriptionFromAttribute(prop) == columnName));
Dapper.SqlMapper.SetTypeMap(typeof(TypeWithMapping), map);

ระดับผู้ช่วยที่จะได้รับชื่อปิดคุณลักษณะคำอธิบาย (ส่วนตัวฉันได้ใช้คอลัมน์เช่น @kalebs ตัวอย่าง)

static string GetDescriptionFromAttribute(MemberInfo member)
{
   if (member == null) return null;

   var attrib = (DescriptionAttribute)Attribute.GetCustomAttribute(member, typeof(DescriptionAttribute), false);
   return attrib == null ? null : attrib.Description;
}

ชั้น

public class TypeWithMapping
{
   [Description("B")]
   public string A { get; set; }

   [Description("A")]
   public string B { get; set; }
}

1
ในการสั่งซื้อเพื่อให้การทำงานแม้สำหรับคุณสมบัติที่ไม่มีคำอธิบายที่ถูกกำหนดให้ผมเปลี่ยนกลับมาของGetDescriptionFromAttributeการreturn (attrib?.Description ?? member.Name).ToLower();และเพิ่ม.ToLower()ไปcolumnNameในแผนที่มันไม่ควรจะเป็นกรณีที่สำคัญ
แซมไวท์

11

การส่งข้อความกับการทำแผนที่คือการเคลื่อนย้ายไปยังดินแดน ORM จริง แทนที่จะต่อสู้กับมันและทำให้ Dapper อยู่ในรูปแบบที่เรียบง่าย (รวดเร็ว) จริง ๆ เพียงแค่ปรับเปลี่ยน SQL ของคุณเล็กน้อยเช่น:

var sql = @"select top 1 person_id as PersonId,FirstName,LastName from Person";

8

ก่อนที่คุณจะเปิดการเชื่อมต่อกับฐานข้อมูลของคุณให้รันโค้ดนี้สำหรับคลาส poco ของคุณแต่ละอัน:

// Section
SqlMapper.SetTypeMap(typeof(Section), new CustomPropertyTypeMap(
    typeof(Section), (type, columnName) => type.GetProperties().FirstOrDefault(prop =>
    prop.GetCustomAttributes(false).OfType<ColumnAttribute>().Any(attr => attr.Name == columnName))));

จากนั้นเพิ่มคำอธิบายประกอบข้อมูลลงในคลาส poco ของคุณดังนี้:

public class Section
{
    [Column("db_column_name1")] // Side note: if you create aliases, then they would match this.
    public int Id { get; set; }
    [Column("db_column_name2")]
    public string Title { get; set; }
}

หลังจากนั้นคุณก็พร้อมแล้ว เพียงโทรออกแบบสอบถามสิ่งที่ชอบ:

using (var sqlConnection = new SqlConnection("your_connection_string"))
{
    var sqlStatement = "SELECT " +
                "db_column_name1, " +
                "db_column_name2 " +
                "FROM your_table";

    return sqlConnection.Query<Section>(sqlStatement).AsList();
}

1
มันต้องการคุณสมบัติทั้งหมดที่จะมีแอตทริบิวต์คอลัมน์ มีวิธีการแมปกับคุณสมบัติในกรณี mapper หรือไม่?
sandeep.gosavi

5

หากคุณใช้. NET 4.5.1 หรือสูงกว่าชำระเงินDapper.FluentColumnMappingสำหรับการแมปลักษณะของ LINQ มันช่วยให้คุณแยกการแม็พ db ออกจากโมเดลของคุณได้อย่างสมบูรณ์ (ไม่จำเป็นต้องมีคำอธิบายประกอบ)


5
ฉันเป็นผู้เขียน Dapper.FluentColumnMapping การแยกการแมปออกจากโมเดลเป็นหนึ่งในเป้าหมายการออกแบบหลัก ฉันต้องการแยกการเข้าถึงข้อมูลหลัก (เช่นที่เก็บอินเทอร์เฟซวัตถุจำลอง ฯลฯ ) จากการใช้งานเฉพาะฐานข้อมูลสำหรับการแยกประเด็นที่ชัดเจน ขอบคุณสำหรับการกล่าวถึงและฉันดีใจที่คุณพบว่ามีประโยชน์! :-)
Alexander

github.com/henkmollema/Dapper-FluentMapคล้ายกัน แต่คุณไม่ต้องการแพ็คเกจของบุคคลที่สามอีกต่อไป Dapper เพิ่ม Dapper.SqlMapper ดูคำตอบของฉันสำหรับรายละเอียดเพิ่มเติมหากคุณสนใจ
Tadej

4

นี่คือลูกหมูที่สนับสนุนคำตอบอื่น ๆ เป็นเพียงความคิดที่ฉันมีสำหรับการจัดการสตริงการสืบค้น

Person.cs

public class Person 
{
    public int PersonId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public static string Select() 
    {
        return $"select top 1 person_id {nameof(PersonId)}, first_name {nameof(FirstName)}, last_name {nameof(LastName)}from Person";
    }
}

วิธีการ API

using (var conn = ConnectionFactory.GetConnection())
{
    var person = conn.Query<Person>(Person.Select()).ToList();
    return person;
}

1

สำหรับทุกคนที่ใช้ Dapper 1.12 นี่คือสิ่งที่คุณต้องทำเพื่อให้เสร็จ:

  • เพิ่มคลาสแอตทริบิวต์คอลัมน์ใหม่:

      [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property]
    
      public class ColumnAttribute : Attribute
      {
    
        public string Name { get; set; }
    
        public ColumnAttribute(string name)
        {
          this.Name = name;
        }
      }

  • ค้นหาบรรทัดนี้:

    map = new DefaultTypeMap(type);

    และแสดงความคิดเห็นออกมา

  • เขียนสิ่งนี้แทน:

            map = new CustomPropertyTypeMap(type, (t, columnName) =>
            {
              PropertyInfo pi = t.GetProperties().FirstOrDefault(prop =>
                                prop.GetCustomAttributes(false)
                                    .OfType<ColumnAttribute>()
                                    .Any(attr => attr.Name == columnName));
    
              return pi != null ? pi : t.GetProperties().FirstOrDefault(prop => prop.Name == columnName);
            });


  • ฉันไม่แน่ใจว่าฉันเข้าใจ - คุณแนะนำให้ผู้ใช้เปลี่ยน Dapper เพื่อให้การแมปแอตทริบิวต์โดยคอลัมน์เป็นไปได้? ถ้าเป็นเช่นนั้นเป็นไปได้โดยใช้รหัสที่ฉันโพสต์ด้านบนโดยไม่ทำการเปลี่ยนแปลง Dapper
    Kaleb Pederson

    1
    แต่คุณจะต้องเรียกใช้ฟังก์ชั่นการแมปสำหรับประเภทรูปแบบแต่ละแบบของคุณใช่ไหม ฉันสนใจโซลูชันทั่วไปเพื่อให้ทุกประเภทของฉันสามารถใช้แอตทริบิวต์ได้โดยไม่ต้องเรียกการแมปสำหรับแต่ละประเภท
    Uri Abramson

    2
    ฉันต้องการดู DefaultTypeMap สามารถใช้งานได้โดยใช้รูปแบบกลยุทธ์เพื่อให้สามารถแทนที่ด้วยเหตุผลที่ @UriAbramson กล่าวถึง ดูcode.google.com/p/dapper-dot-net/issues/detail?id=140
    Richard Collette

    1

    วิธีแก้ปัญหาของ Kaleb Pederson เหมาะสำหรับฉัน ฉันอัปเดต ColumnAttributeTypeMapper เพื่ออนุญาตแอตทริบิวต์ที่กำหนดเอง (มีข้อกำหนดสำหรับการแมปที่แตกต่างกันสองรายการบนวัตถุโดเมนเดียวกัน) และคุณสมบัติที่อัปเดตเพื่ออนุญาตให้ผู้ตั้งค่าส่วนตัวในกรณีที่จำเป็นต้องได้รับฟิลด์และประเภทแตกต่างกัน

    public class ColumnAttributeTypeMapper<T,A> : FallbackTypeMapper where A : ColumnAttribute
    {
        public ColumnAttributeTypeMapper()
            : base(new SqlMapper.ITypeMap[]
                {
                    new CustomPropertyTypeMap(
                       typeof(T),
                       (type, columnName) =>
                           type.GetProperties( BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).FirstOrDefault(prop =>
                               prop.GetCustomAttributes(true)
                                   .OfType<A>()
                                   .Any(attr => attr.Name == columnName)
                               )
                       ),
                    new DefaultTypeMap(typeof(T))
                })
        {
            //
        }
    }

    1

    ฉันรู้ว่านี่เป็นหัวข้อที่ค่อนข้างเก่า แต่ฉันคิดว่าฉันจะทิ้งสิ่งที่ฉันทำไว้ที่นั่น

    ฉันต้องการทำแผนที่แอตทริบิวต์ให้ทำงานทั่วโลก ไม่ว่าคุณจะตรงกับชื่อคุณสมบัติ (ค่าเริ่มต้น aka) หรือคุณตรงกับแอตทริบิวต์คอลัมน์ในคุณสมบัติชั้นเรียน ฉันไม่ต้องการตั้งค่านี้สำหรับทุกชั้นที่ฉันทำแผนที่ด้วย ดังนั้นฉันจึงสร้างคลาส DapperStart ที่ฉันเรียกใช้เมื่อเริ่มต้นแอพ:

    public static class DapperStart
    {
        public static void Bootstrap()
        {
            Dapper.SqlMapper.TypeMapProvider = type =>
            {
                return new CustomPropertyTypeMap(typeof(CreateChatRequestResponse),
                    (t, columnName) => t.GetProperties().FirstOrDefault(prop =>
                        {
                            return prop.Name == columnName || prop.GetCustomAttributes(false).OfType<ColumnAttribute>()
                                       .Any(attr => attr.Name == columnName);
                        }
                    ));
            };
        }
    }

    ค่อนข้างง่าย ไม่แน่ใจว่ามีปัญหาอะไรที่ฉันจะเจอในขณะที่ฉันเพิ่งเขียนสิ่งนี้ แต่ใช้งานได้


    CreateChatRequestResponse มีลักษณะอย่างไร นอกจากนี้คุณจะเรียกมันอย่างไรในการเริ่มต้น?
    เกลน F.

    1
    @GlenF จุดคือมันไม่สำคัญว่า CreateChatRequestResponse ดูเหมือนว่า มันสามารถเป็น POCO ใดก็ได้ สิ่งนี้จะถูกเรียกใช้ในการเริ่มต้นของคุณ คุณสามารถเรียกใช้แอพของคุณได้จาก StartUp.cs หรือ Global.asax
    Matt M

    บางทีฉันผิดอย่างสมบูรณ์ แต่ถ้าไม่CreateChatRequestResponseถูกแทนที่ด้วยTสิ่งนี้จะทำซ้ำผ่านวัตถุทั้งหมด โปรดแก้ไขฉันหากฉันผิด
    Fwd079

    0

    วิธีแก้ไขปัญหาอย่างง่าย Kaleb พยายามแก้ไขคือเพียงยอมรับชื่อคุณสมบัติหากไม่มีคอลัมน์แอตทริบิวต์:

    Dapper.SqlMapper.SetTypeMap(
        typeof(T),
        new Dapper.CustomPropertyTypeMap(
            typeof(T),
            (type, columnName) =>
                type.GetProperties().FirstOrDefault(prop =>
                    prop.GetCustomAttributes(false)
                        .OfType<ColumnAttribute>()
                        .Any(attr => attr.Name == columnName) || prop.Name == columnName)));
    
    โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
    Licensed under cc by-sa 3.0 with attribution required.