Problème à propos de Dapper

dapper map orm

Question

public class Profile
{
    public int ID { get; set; }

    public string Name { get; set; }

    public string Phone { get; set; }

    public string Address { get; set; }

    public ExtraInfo Extra { get; set; }
}

public class Topic
{
    public int ID { get; set; }

    public string Title { get; set; }

    public DateTime CreateDate { get; set; }

    public string Content { get; set; }

    public int UID { get; set; }

    public int TestColum { get; set; }

    public string Name { get; set; }

    public Profile Author { get; set; }

    public Attachment Attach { get; set; }
}

correct:

var list = conn.Query<Topic, Profile, Topic>(
            @"select top 3 
                T.ID,
                T.Title,
                T.CreateDate,
                P.Phone,
                P.Name
            from Topic as T
            inner join Profile P on T.UID = P.ID",
            (T, P) => { T.Author = P; return T; },
            null,
            null,
            true,
            "Phone");

lancer une exception sur la ligne SqlMapper.cs 2177:

var list = conn.Query<Topic, Profile, Topic>(
            @"select top 3 
                T.ID,
                T.Title,
                T.CreateDate,
                P.Name,
                P.Phone
            from Topic as T
            inner join Profile P on T.UID = P.ID",
            (T, P) => { T.Author = P; return T; },
            null,
            null,
            true,
            "Name");

Maintenant, je supprime la propriété "Nom" du sujet, qui sera correcte.

Je pense que la clé est à la ligne SqlMapper.cs 1153

int current = 0;
var splits = splitOn.Split(',').ToArray();
var splitIndex = 0;

Func<Type, int> nextSplit = type =>
{
    var currentSplit = splits[splitIndex].Trim();
    if (splits.Length > splitIndex + 1)
    {
        splitIndex++;
    }

    bool skipFirst = false;
    int startingPos = current + 1;
    // if our current type has the split, skip the first time you see it. 
    if (type != typeof(Object))
    {
        var props = DefaultTypeMap.GetSettableProps(type);
        var fields = DefaultTypeMap.GetSettableFields(type);

        foreach (var name in props.Select(p => p.Name).Concat(fields.Select(f => f.Name)))
        {
            if (string.Equals(name, currentSplit, StringComparison.OrdinalIgnoreCase))
            {
                skipFirst = true;
                startingPos = current;
                break;
            }
        }

    }

    int pos;
    for (pos = startingPos; pos < reader.FieldCount; pos++)
    {
        // some people like ID some id ... assuming case insensitive splits for now
        if (splitOn == "*")
        {
            break;
        }
        if (string.Equals(reader.GetName(pos), currentSplit, StringComparison.OrdinalIgnoreCase))
        {
            if (skipFirst)
            {
                skipFirst = false;
            }
            else
            {
                break;
            }
        }
    }
    current = pos;
    return pos;
};

"Si notre type actuel a le partage, ignorez la première fois que vous le voyez."

Lorsque "current type" a une propriété qui s'appelle "split", mais que nous n'avons pas sélectionné ce champ à partir de db, dapper lancera une exception.

Ceci est un problème de conception, ou je ne suis pas utilisé correctement?

Réponse acceptée

Sur la base de votre édition, il semble en effet que ce scénario devrait être mieux géré. il serait intéressant de consigner cela comme un bogue sur le site du projet - car cela est assez subtil, et il faut réfléchir à la manière de résoudre le problème.

Il semble que cela devrait fonctionner, et j'ai du mal à le faire échouer avec le code que vous affichez - le suivant fonctionne correctement (testé avec le code 1.13):

public void TestSplitWithMissingMembers()
{
    var result = connection.Query<Topic, Profile, Topic>(
    @"select 123 as ID, 'abc' as Title,
             cast('01 Feb 2013' as datetime) as CreateDate,
             'def' as Phone, 'ghi' as Name",
    (T, P) => { T.Author = P; return T; },
    splitOn: "Phone").Single();

    result.ID.Equals(123);
    result.Title.Equals("abc");
    result.CreateDate.Equals(new DateTime(2013, 2, 1));
    result.Name.IsNull();
    result.Content.IsNull();

    result.Author.Phone.Equals("def");
    result.Author.Name.Equals("ghi");
    result.Author.ID.Equals(0);
    result.Author.Address.IsNull();
}

Note j'ai ajouté:

public Profile Author { get; set; }

to Topic , mais sinon le code est identique. Y a-t-il une chance que le problème ait changé entre votre code actuel et votre code exemple ? Heureux d'enquêter, mais je dois savoir que je regarde la bonne chose.


Réponse populaire

Je pense que votre seul problème lorsque vous divisez par "Téléphone" est que vous devez d'abord sélectionner P.Phone:

 @"select top 3 
                T.ID,
                T.Title,
                T.CreateDate,
                P.Phone,
                P.Name

            from Topic as T
            inner join Profile P on T.UID = P.ID",



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi