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将抛出异常。
这是一个设计问题,或者我使用不正确?
答案 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",