2011-02-16 46 views
8

以下爲僞代碼:SQLCE - Upsert(更新或插入) - 如何使用常用方法準備行?

SqlCeResultSet myResultSet = cmd.ExecuteResultSet(Options...etc); 
bool found = myResultSet.Seek(); 
if found { 
    //do an Update 
    myResultSet.Read() //make current 

    //At this point we have a cursor positioned at a row to be edited 
    myResultSet.SetString(1, "value for col 1"); 
    myResultSet.SetString(2, "value for col 2"); 
    //... etc... 
    myResultSet.SetString(100, "value for col 100"); 
    //i want to replace above with: CommonMethodToFillRowData(someRow) 

    //finally update 
    myResultSet.Update(); 

} else { 
    //do an insert 
    SqlCeUpdatableRecord myRec = myResultSet.CreateRecord(); 
    //set primaryKey 
    myRec.SetInt32(0, pkValue); 

    //At this point we have a cursor positioned at a row to be edited 
    myRec.SetString(1, "value for col 1"); 
    myRec.SetString(2, "value for col 2"); 
    //... etc... 
    myRec.SetString(100, "value for col 100"); 
    //i want to replace above with: CommonMethodToFillRowData(someRow) 

    //finally insert 
    myResultSet.Insert(myRec); 
} 

根據上述內容,如果我有100列的準備,它必須被重複兩次;我想要的是一些CommonMethodToFillRowData();但是,我使用這種方法的參數類型是什麼?

CommonMethodToFillRowData(SqlCeResultSet or SqlCeUpdatableRecord ? parmRow) { 
    parmRow.SetInt32(col1, value1) 
    parmRow.SetString(col2, value2) 
    ...etc. 
    parmRow.SetString(100, "value for col 100"); 
} 

從MSDN DOCO直接引用上SqlCeUpdatableRecord類別: - >表示從數據源可更新的值的行。 SqlCeResultSet對象包含一個或多個UpdatableRecords。

如果是這樣,爲什麼我不能直接訪問SqlCeResultSet中的單個UpdatableRecord,一旦我通過Seek()定位遊標?

如果這是可能的,這將使我的使用方法:

CommonMethodToFillRowData(SqlCeUpdatableRecord parmRow) { 
    //end of story 
} 
+1

你是怎麼得到這個JoeDotNot? – ETFairfax 2011-02-28 22:40:32

+0

我也被捕了... – 2011-03-31 07:28:15

+0

@Sébastien - 請參閱我的「最後一分鐘」的答案。 – Greg 2011-04-07 04:46:29

回答

3

創建一個包裝對象,可以代表SqlCeResultSetSqlCeUpdatableRecord適當。然後編寫一次「保存」代碼,並將其作爲更新或插入應用,具體取決於記錄是否已經存在。

警告:這是代碼未經測試。

public void SavingMyData() 
{ 
    SqlCeResultSet resultSet = cmd.ExecuteResultSet(Options...etc); 
    SqlCeWrapper wrapper = new SqlCeWrapper(resultSet); 

    wrapper.SetInt32(0, pkValue, true); // Primary Key = true 
    wrapper.SetString(1, "value for col 1"); 
    wrapper.SetString(2, "value for col 2"); 
    wrapper.SetString(100, "value for col 100"); 
    wrapper.Commit(); 
} 

... 

public class SqlCeWrapper 
{ 
    private readonly bool _found; 
    private readonly SqlCeResultSet _resultSet; 
    private readonly SqlCeUpdatableRecord _newRecord; 

    public SqlCeWrapper(SqlCeResultSet resultSet) 
    { 
     _resultSet = resultSet; 

     _found = resultSet.Seek(); 
     if (_found) 
      resultSet.Read(); 
     else 
      _newRecord = resultSet.CreateRecord(); 
    } 

    public void SetInt32(int ordinal, int value, bool isPrimary = false) 
    { 
     if (_found && !isPrimary) 
      _resultSet.SetInt32(ordinal, value); 
     else if (!_found) 
      _newRecord.SetInt32(ordinal, value); 
    } 

    public void SetString(int ordinal, string value, bool isPrimary = false) 
    { 
     if (_found && !isPrimary) 
      _resultSet.SetString(ordinal, value); 
     else if (!_found) 
      _newRecord.SetString(ordinal, value); 
    } 

    public void Commit() 
    { 
     if (_found) 
      _resultSet.Update(); 
     else 
      _resultSet.Insert(_newRecord); 
    } 
} 

注:如果您不使用.NET 4,你必須刪除可選參數。根據您的需要,您還可以添加額外的SetX()方法到SqlCeWrapper

3

如何:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Data.SqlServerCe; 
using System.Collections; 
using System.Data; 

namespace SqlCeRecord_Test 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      // Arguments for update 
      int lookFor = 1; 
      string value = "AC/DC"; 

      // Arguments for insert 
      lookFor = Int16.MaxValue; 
      value = "joedotnet"; 

      using (SqlCeConnection conn = new SqlCeConnection(@"Data Source=C:\Users\xeej\Downloads\ChinookPart2\Chinook.sdf")) 
      { 
       conn.Open(); 

       using (SqlCeCommand cmd = new SqlCeCommand("Artist")) 
       { 
        SqlCeUpdatableRecord myRec = null; 
        cmd.Connection = conn; 
        cmd.CommandType = System.Data.CommandType.TableDirect; 
        cmd.IndexName = "PK_Artist"; 
        SqlCeResultSet myResultSet = cmd.ExecuteResultSet(ResultSetOptions.Updatable | ResultSetOptions.Scrollable); 
        bool found = myResultSet.Seek(DbSeekOptions.FirstEqual, new object[] { lookFor }); 

        if (found) 
        { 
         myResultSet.Read(); 
        } 
        else 
        { 
         myRec = myResultSet.CreateRecord(); 
        } 
        foreach (KeyValuePair<int, object> item in CommonMethodToFillRowData(value)) 
        { 
         if (found) 
         { 
          myResultSet.SetValue(item.Key, item.Value); 
         } 
         else 
         { 
          myRec.SetValue(item.Key, item.Value); 
         } 
        } 
        if (found) 
        { 
         myResultSet.Update(); 
        } 
        else 
        { 
         myResultSet.Insert(myRec); 
        } 
       } 
      } 
     } 

     private static Dictionary<int, object> CommonMethodToFillRowData(string value1) //TODO add more values 
     { 
      var dict = new Dictionary<int, object>(); 
      dict.Add(1, value1); 
      return dict; 
     } 
    } 
} 
+0

好吧,你仍然必須重複兩次foreach循環... – 2011-04-06 07:48:58

+1

現在一個單一的foreach循環 – ErikEJ 2011-04-06 10:55:48

1

我不知道你想要做什麼,我不知道特別是關於這些組件,所以可能會有更高效的方法。但根據MSDN,SqlCeResultSetSqlCeDataReader,它是一個DbDataReader,它實現IDataRecord ...和SqlCeUpdateableRecord也實現IDataRecord

那麼,這是否工作?

public static void DoStuff() 
{ 
    SqlCeCommand cmd = new SqlCeCommand(); 
    SqlCeResultSet myResultSet = cmd.ExecuteResultSet(ResultSetOptions.None); 
    var reader = myResultSet.Read(); 

    bool found = myResultSet.Seek(DbSeekOptions.After); 
    if (found) 
    { 
     myResultSet.Read(); 
     CommonMethodToFillRowData(myResultSet); 
     myResultSet.Update(); 
    } 
    else 
    { 
     SqlCeUpdatableRecord myRec = myResultSet.CreateRecord(); 
     CommonMethodToFillRowData(myRec); 
     myResultSet.Insert(myRec); 
    } 
} 

// All the messy Type-wrangling is hidden behind the scenes 
public static void CommonMethodToFillRowData(this IDataRecord RowToFill) 
{ 
    RowToFill.SetInt32(1, 42); 
    RowToFill.SetString(2, "Foo"); 
    // etc... 
} 

// Since SetInt32 seems to do the same thing in either inherited Type 
public static void SetInt32(this IDataRecord RowToFill, int Ordinal, int Value) 
{ 
    Type rowType = RowToFill.GetType(); 
    if (rowType == typeof(SqlCeResultSet)) 
     ((SqlCeResultSet)RowToFill).SetInt32(Ordinal, Value); 
    else if (rowType == typeof(SqlCeUpdatableRecord)) 
     ((SqlCeUpdatableRecord)RowToFill).SetInt32(Ordinal, Value); 
    else 
     throw new ArgumentException("Method does not know what to do with Type " + rowType.ToString()); 
} 

// Since SetString seems to do the same thing in either inherited Type 
public static void SetString(this IDataRecord RowToFill, int Ordinal, string Value) 
{ 
    Type rowType = RowToFill.GetType(); 
    if (rowType == typeof(SqlCeResultSet)) 
     ((SqlCeResultSet)RowToFill).SetString(Ordinal, Value); 
    else if (rowType == typeof(SqlCeUpdatableRecord)) 
     ((SqlCeUpdatableRecord)RowToFill).SetString(Ordinal, Value); 
    else 
     throw new ArgumentException("Method does not know what to do with Type " + rowType.ToString()); 
} 

這是骯髒和性能將不會很大,但它可能做你要找什麼,如果你想要做的是摺疊列式灌裝成一個代碼段。

2

如何使用在SqlCeResultSet而不是Read方法枚舉這樣

IEnumerator enumerator = myResultSet.GetEnumerator(); 
bool found = enumerator.MoveNext(); 
SqlCeUpdatableRecord record; 
if (found) { 
    record = (SqlCeUpdatableRecord)enumerator.Current; 
    MethodToFill(record); 
    myResultSet.Update(); 
} else { 
    record = myResultSet.CreateRecord(); 
    MethodToFill(record); 
    myResultSet.Insert(record); 
} 

private void MethodToFill(SqlCeUpdatableRecord recordToFill) { 
    recordToFill.SetString(0, "Hello"); 
    recordToFill.SetString(1, "World"); 
    // etc 
}