2
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; }
}

正确:</p>

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");

在 SqlMapper.cs 第 2177 行抛出异常:</p>

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");

现在,我删除了主题的属性“名称”,这将是正确的。

我认为关键在 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;
};

“如果我们目前的类型有拆分,第一次看到就跳过。”

当“当前类型”有一个名称等于“split”的属性,但我们没有从db中选择这个字段时,dapper会抛出异常。

这是设计问题,还是我没有正确使用?

4

2 回答 2

1

根据您的编辑,确实看起来这是一个应该更好地处理的场景;值得将其作为错误记录在项目站点上 - 因为这是非常微妙的,并且决定解决此问题的正确方法需要一些思考。

看起来它应该可以工作,并且我很难使用您显示的代码使其失败 - 以下工作正常(使用 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();
}

注意我补充说:

public Profile Author { get; set; }

Topic,但除此之外代码是相同的。您的实际代码和示例代码之间的问题是否有可能发生变化?很高兴调查,但我需要知道我正在寻找正确的东西。

于 2013-06-06T07:08:30.417 回答
0

我认为当您按“电话”拆分时,您唯一的问题是您应该首先选择 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",
于 2013-06-06T07:21:29.077 回答