Вставка коллекции IEnumerable <T>с ошибками Dapper с помощью «class не поддерживается Dapper». - PullRequest
31 голосов
/ 17 июня 2011

Да, здесь есть вопросы и здесь о том, как вставлять записи с помощью dapper-dot-net. Однако ответы, хотя и информативные, похоже, не указали мне правильное направление. Вот ситуация: перемещение данных из SqlServer в MySql. Чтение записей в IEnumerable<WTUser> легко, но я просто не получаю что-то на вкладыше. Во-первых, «код движущихся записей»:

//  moving data
Dim session As New Session(DataProvider.MSSql, "server", _
                           "database")

Dim resources As List(Of WTUser) = session.QueryReader(Of WTUser)("select * from tbl_resource")


session = New Session(DataProvider.MySql, "server", "database", _
                      "user", "p@$$w0rd")

//    *edit* - corrected parameter notation with '@'
Dim strInsert = "INSERT INTO tbl_resource (ResourceName, ResourceRate, ResourceTypeID, ActiveYN) " & _
                "VALUES (@ResourceName, @ResourceRate, @ResourceType, @ActiveYN)"

Dim recordCount = session.WriteData(Of WTUser)(strInsert, resources)

//  session Methods
    Public Function QueryReader(Of TEntity As {Class, New})(ByVal Command As String) _
                                                            As IEnumerable(Of TEntity)
        Dim list As IEnumerable(Of TEntity)

        Dim cnn As IDbConnection = dataAgent.NewConnection
        list = cnn.Query(Of TEntity)(Command, Nothing, Nothing, True, 0, CommandType.Text).ToList()

        Return list
    End Function

    Public Function WriteData(Of TEntity As {Class, New})(ByVal Command As String, ByVal Entities As IEnumerable(Of TEntity)) _
                                                          As Integer
        Dim cnn As IDbConnection = dataAgent.NewConnection

        //    *edit* if I do this I get the correct properties, but no data inserted
        //Return cnn.Execute(Command, New TEntity(), Nothing, 15, CommandType.Text)

        //    original Return statement
        Return cnn.Execute(Command, Entities, Nothing, 15, CommandType.Text)
    End Function

cnn.Query и cnn.Execute вызывают методы расширения dapper. Теперь класс WTUser (примечание: имя столбца изменилось с «WindowsName» в SqlServer на «ResourceName» в MySql, таким образом, два свойства указывают на одно и то же поле):

Public Class WTUser
    //    edited for brevity - assume the following all have public get/set methods
    Public ActiveYN As String
    Public ResourceID As Integer
    Public ResourceRate As Integer
    Public ResourceType As Integer
    Public WindowsName As String
    Public ResourceName As String

End Class

Я получаю исключение от dapper: «WTUser не поддерживается Dapper». Этот метод в DataMapper (dapper):

    private static Action<IDbCommand, object> CreateParamInfoGenerator(Type OwnerType)
    {
        string dmName = string.Format("ParamInfo{0}", Guid.NewGuid());
        Type[] objTypes = new[] { typeof(IDbCommand), typeof(object) };

        var dm = new DynamicMethod(dmName, null, objTypes, OwnerType, true); // << - here
        //    emit stuff

        //    dm is instanced, now ...
        foreach (var prop in OwnerType.GetProperties().OrderBy(p => p.Name))

На данный момент OwnerType =

System.Collections.Generic.List`1 [[CRMBackEnd.WTUser, CRMBE, версия = 1.0.0.0, Culture = нейтрально, PublicKeyToken = null]], mscorlib, Версия = 2.0.0.0, Культура = нейтральная, PublicKeyToken = b77a5c561934e089

Кажется, что OwnerType должен быть CRMBackEnd.WTUser ... не List<CRMBackEnd.WTUser> ... ??? потому что происходит то, что свойства коллекции перебираются: количество, емкость и т. д. Что мне не хватает?

Обновление

Если я изменил session.WriteData как:

Public Function WriteData(Of TEntity As {Class, New})(ByVal Command As String, _
                                                      ByVal Entities As IEnumerable(Of TEntity)) _
                                                      As Integer
    Dim cnn As IDbConnection = dataAgent.NewConnection
    Dim records As Integer

    For Each entity As TEntity In Entities
        records += cnn.Execute(Command, entity, Nothing, 15, CommandType.Text)
    Next

    Return records
End Function

записи вставлены красиво ... но я не думаю, что это будет необходимо, учитывая примеры, такие как:

connection.Execute(@"insert MyTable(colA, colB) values (@a, @b)",
    new[] { new { a=1, b=1 }, new { a=2, b=2 }, new { a=3, b=3 } }
  ).IsEqualTo(3); // 3 rows inserted: "1,1", "2,2" and "3,3"  

... из dapper-dot-net

1 Ответ

47 голосов
/ 28 июня 2011

Я только что добавил тест для этого:

class Student
{
    public string Name {get; set;}
    public int Age { get; set; }
}

public void TestExecuteMultipleCommandStrongType()
{
    connection.Execute("create table #t(Name nvarchar(max), Age int)");
    int tally = connection.Execute(@"insert #t (Name,Age) values(@Name, @Age)", new List<Student> 
    {
        new Student{Age = 1, Name = "sam"},
        new Student{Age = 2, Name = "bob"}
    });
    int sum = connection.Query<int>("select sum(Age) from #t drop table #t").First();
    tally.IsEqualTo(2);
    sum.IsEqualTo(3);
}

Он работает как рекламируется.Я внес несколько поправок в работу multi-exec (так что он работает немного быстрее и поддерживает object []).

Полагаю, у вас возникли проблемы, поскольку вы пропустили свойство getter во всех ваших полях WTUser.Все параметры должны иметь свойства читателя, мы не поддерживаем извлечение этого из полей, это потребует сложного шага синтаксического анализа, чтобы оставаться эффективным.


Дополнительным моментом, вызвавшим проблему, является передача dapper параметра с неподдерживаемым отображением.

Например, следующий класс не поддерживается в качестве параметра:

class Test
{
   public int Id { get; set; }
   public User User {get; set;}
}

cnn.Query("select * from Tests where Id = @Id", new Test{Id = 1}); // used to go boom 

Проблема в том, что dapper не анализировал SQL, предполагал, что все реквизиты можно задавать как params, но не смог разрешить тип SQL для User.

Последняя версия исправляет это

...