关于dapper的问题

时间:2013-06-06 06:41:55

标签: orm map dapper

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

正确的:

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行抛出异常:

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

现在,我删除了Topic的属性“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将抛出异常。

这是一个设计问题,或者我使用不正确?

2 个答案:

答案 0 :(得分: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,但代码是相同的。您的实际代码和示例代码之间的问题是否有可能发生变化?很高兴调查,但我需要知道我正在寻找正确的事情。

答案 1 :(得分: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",