2013-06-06 65 views
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; } 
} 

正確:發行約短小精悍

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

現在,我刪除主題的 「名稱」 屬性,這將是正確的。

我覺得關鍵是在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會拋出一個異常。

這是設計問題,或者我使用不正確?

回答

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,但其他代碼是相同的。您的實際代碼與您的示例代碼之間是否有任何問題發生了變化?很高興進行調查,但我需要知道我正在尋找正確的事情。

+0

我編輯的問題already.You可以看看問題又來。 –

+0

你不應該把splitOn設置爲「Phone」,你可以將它設置爲「Name」。如果我們只需要Profile的Name,你將會看到一個異常。 –

+0

@空葫蘆看到我最近的編輯 –

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", 
相關問題