English 中文(简体)
How would you refactor this bit of code?
原标题:

This bit of code runs on Windows Compact Framework and what it does is obvious. It looks as it should be refactored (especially considering that I may want to add cmd.ExecuteResultSet() later), but I can t see an elegant way to do it. Any ideas appreciated.

internal void RunNonQuery(string query)
{
    string connString = GetLocalConnectionString();

    using (SqlCeConnection cn = new SqlCeConnection(connString))
    {
        cn.Open();
        SqlCeCommand cmd = cn.CreateCommand();
        cmd.CommandText = query;
        cmd.ExecuteNonQuery();
    }
}  

internal int RunScalar(string query)  
{
    string connString = GetLocalConnectionString();

    using (SqlCeConnection cn = new SqlCeConnection(connString))
    {
        cn.Open();
        SqlCeCommand cmd = cn.CreateCommand();
        cmd.CommandText = query;
        return int.Parse(cmd.ExecuteScalar().ToString());
    }
}
最佳回答

I m not sure I would refactor it, but perhaps:

static void PerformQuery(string connectionString, string command,
      Action<SqlCeCommand> action)
{ //TODO: sanity checks...
    using(SqlCeConnection conn = new SqlCeConnection(connectionString))
    using(SqlCeCommand cmd = conn.CreateCommand()) {
        cmd.CommandText = command;
        conn.Open();
        action(cmd);
    }
}

internal void RunNonQuery(string query)
{
    string connString = GetLocalConnectionString();
    PerformQuery(connString, query, cmd => cmd.ExecuteNonQuery());
}  

internal int RunScalar(string query)  
{
    int result = 0;
    string connString = GetLocalConnectionString();
    PerformQuery(connString, query,
        cmd => {result = int.Parse(cmd.ExecuteScalar().ToString()); }
    );
    return result;
}

Otherwise - just maybe a CreateAndOpenConnection(string) method, and a CreateCommand(SqlCeConnection,string) method.

问题回答

If you are using C# 3.0, you could do something like the following:

private T CreateCommand<T>(string query, Func<SqlCeCommand, T> func)
{
    var connString = GetLocalConnectionString();

    using (var cn = new SqlCeConnection(connString))
    {
        cn.Open();

        using (var cmd = cn.CreateCommand())
        {
            cmd.CommandText = query;
            return func(cmd);
        }
    }
}

private void CreateCommand(string query, Action<SqlCeCommand> action)
{
    CreateCommand<object>(query, cmd => 
    {
        action(cmd);
        return null;
    });
}

internal void RunNonQuery(string query)
{
    CreateCommand(query, cmd => cmd.ExecuteNonQuery());
}

internal int RunScalar(string query)
{
    return CreateCommand(query, cmd => 
        int.Parse(cmd.ExecuteScalar().ToString()));
}    

I would create a class out of the code to wrap the connection creation and command execution logic. This will provide you with a single place to implement transactions in the future and will consolidate creation of the connection and command. This consolidation will allow for settings timeouts, joining transactions, etc.

class Connection : IDisposable
{
    readonly SqlConnection _conn;
    public Connection()
    {
        string connString = GetLocalConnectionString();
        _conn = new SqlConnection(connString);
        _conn.Open();
    }

    public void Dispose() { _conn.Dispose(); }

    public SqlCommand CreateCommand(string qry)
    {
        SqlCommand cmd = _conn.CreateCommand();
        cmd.CommandText = qry;
        //cmd.CommandTimeout = TimeSpan.FromMinutes(x);
        return cmd;
    }
    public int ExecuteNonQuery(string qry)
    {
        using (SqlCommand cmd = CreateCommand(qry))
            return cmd.ExecuteNonQuery();
    }
    public int RunScalar(string qry)
    {
        using (SqlCommand cmd = CreateCommand(qry))
            return int.Parse(cmd.ExecuteScalar().ToString());
    }
}

Then if you still want to maintain your original API, you do the following:

class SqlCode
{
    internal void RunNonQuery(string query)
    {
        using (Connection cn = new Connection())
            cn.ExecuteNonQuery(query);
    }

    internal int RunScalar(string query)
    {
        using (Connection cn = new Connection())
            return cn.RunScalar(query);
    }
}

The only thing left is to re-insert the Ce in the SqlXxxx stuff ;)





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签