我正在使用F#訪問數據庫,我最初嘗試創建一個函數來創建更新查詢是有缺陷的。更多FP正確的方式來創建更新SQL查詢
let BuildUserUpdateQuery (oldUser:UserType) (newUser:UserType) =
let buf = new System.Text.StringBuilder("UPDATE users SET ");
if (oldUser.FirstName.Equals(newUser.FirstName) = false) then buf.Append("SET first_name='").Append(newUser.FirstName).Append("'") |> ignore
if (oldUser.LastName.Equals(newUser.LastName) = false) then buf.Append("SET last_name='").Append(newUser.LastName).Append("'") |> ignore
if (oldUser.UserName.Equals(newUser.UserName) = false) then buf.Append("SET username='").Append(newUser.UserName).Append("'") |> ignore
buf.Append(" WHERE id=").Append(newUser.Id).ToString()
這並不正確放置任何更新部分之間的,
後的第一個,例如:
UPDATE users SET first_name='Firstname', last_name='lastname' WHERE id=...
我可以把一個可變變量來跟蹤時set
的第一部分子句被追加,但這似乎是錯誤的。
我可以創建一個元組列表,其中每個元組都是oldtext,newtext,columnname,這樣我就可以遍歷列表並構建查詢,但似乎應該將StringBuilder
傳遞給一個遞歸函數,返回一個boolean
然後作爲參數傳遞給遞歸函數。
這似乎是最好的方法,還是有更好的?
UPDATE:
下面是我在用我的當前的解決方案,因爲我想讓它更廣義的,所以我只需要編寫一個抽象類,我的實體從獲得和他們能使用相同的功能。我選擇分離我如何執行此功能,以便我可以傳遞如何創建更新的SET
部分,以便我可以測試不同的想法。
let BuildUserUpdateQuery3 (oldUser:UserType) (newUser:UserType) =
let properties = List.zip3 oldUser.ToSqlValuesList newUser.ToSqlValuesList oldUser.ToSqlColumnList
let init = false, new StringBuilder()
let anyChange, (formatted:StringBuilder) =
properties |> Seq.fold (fun (anyChange, sb) (oldVal, newVal, name) ->
match(oldVal=newVal) with
| true -> anyChange, sb
| _ ->
match(anyChange) with
| true -> true, sb.AppendFormat(",{0} = '{1}'", name, newVal)
| _ -> true, sb.AppendFormat("{0} = '{1}'", name, newVal)
) init
formatted.ToString()
let BuildUserUpdateQuery (oldUser:UserType) (newUser:UserType) (updatequery:UserType->UserType->String) =
let buf = StringBuilder("UPDATE users SET ");
buf.AppendFormat(" {0} WHERE id={1}", (updatequery oldUser newUser), newUser.Id)
let UpdateUser conn (oldUser:UserType) (newUser:UserType) =
let query = BuildUserUpdateQuery oldUser newUser BuildUserUpdateQuery3
execNonQuery conn (query.ToString())
另外請注意,這將返回'string option'而不是'string',就像在原始函數中一樣,以覆蓋無需更新的情況。 – 2010-05-07 03:01:43
如果使用Seq.fold而不是Seq.map,則可以累積結果,之後不需要過濾器,並且可以推遲Seq.toArray,直到最後一個else子句,然後僅測試properties.Any。 – 2010-05-07 06:47:32
謝謝你的回答。我會將其更改爲使用準備好的語句,但實際上,一旦我得到更新語句,這就是一個細節。 – 2010-05-07 10:22:23