繁体   English   中英

我可以将其合并为通用方法吗?

[英]Can I consolidate this in a generic method?

我有一个具有以下2种数据访问方法的DataAccessBase类。 一种用于ExecuteScalar,另一种用于ExecuteNonQuery。 是否有可能将其合并为一种通用方法,甚至值得担心?

    protected static int ExecuteNonQuery(SqlCommand command)
    {
        using (SqlConnection connection = new SqlConnection(_connStr))
        {
            command.Connection = connection;
            SqlDataAdapter da = new SqlDataAdapter(command);
            command.Connection.Open();

            int result = command.ExecuteNonQuery();

            return result;
        }
    }

    protected static string ExecuteScalar(SqlCommand command)
    {
        using (SqlConnection connection = new SqlConnection(_connStr))
        {
            command.Connection = connection;
            SqlDataAdapter da = new SqlDataAdapter(command);
            command.Connection.Open();

            string result = command.ExecuteScalar().ToString();

            return result;
        }
    }

    private static DataTable GetDT(int id)
    {
        using (SqlConnection connection = new SqlConnection(_connStr))
        {
            string query = "select id, userid, name from tasks where id = @id";
            SqlCommand command = new SqlCommand(query, connection);
            SqlDataAdapter da = new SqlDataAdapter(command);
            //Parameterized query to prevent injection attacks
            command.Parameters.AddWithValue("id", id);
            DataTable dt = new DataTable();
            da.Fill(dt);

            return dt;
        }
    }

您绝对可以避免使用通用方法进行的当前重复,但是我不会尝试将其简化为单个方法。 这是我可能要做的:

protected static int ExecuteNonQuery(SqlCommand command) =>
    ExecuteCommand(command, cmd => cmd.ExecuteNonQuery());

protected static string ExecuteScalar(SqlCommand command) =>
    ExecuteCommand(command, cmd => cmd.ExecuteScalar().ToString());

private static T ExecuteCommand<T>(SqlCommand command, Func<SqlCommand, T> resultRetriever)
{
    using (SqlConnection connection = new SqlConnection(_connStr))
    {
        command.Connection = connection;
        command.Connection.Open();
        return resultRetriver(command);
    }
}

对于DataTable ,按照相同的模式,首先创建命令:

protected static DataTable GetDataTable(SqlCommand command) =>
    ExecuteCommand(cmd =>
    {
        SqlDataAdapter da = new SqlDataAdapter(cmd)
        DataTable table = new DataTable();
        da.FillTable(table);
        return table;
    });

您可以将ExecuteScalar转换为通用方法,从而可以更改返回类型。

public T ExecuteScalar<T>(SqlCommand command)
{
    using (SqlConnection connection = new SqlConnection(_connStr))
    {
        command.Connection = connection;
        //SqlDataAdapter da = new SqlDataAdapter(command); //not needed...
        command.Connection.Open();
        var result = command.ExecuteScalar();

        //rather than just returning result with an implicit cast, use Max's trick from here: https://stackoverflow.com/a/2976427/361842
        if (Convert.IsDbNull(result))
            return default(T); //handle the scenario where the returned value is null, but the type is not nullable (or remove this to have such scenarios throw an exception)
        if (result is T)
            return (T)result;
        else
            (T)Convert.ChangeType(result, typeof(T));
    }
}

但是,此方法的逻辑与ExecuteNonQuery函数中的逻辑不同,因此不能用相同的方法来表示两者。


更新资料

关于您对数据表的问题,我采用并改编了@JonSkeet的答案,以允许该类也处理数据表:

public class SqlDatabaseThing //: ISqlDatabaseThing
{

    // ... additional code here ... //

    public int ExecuteNonQuery(SqlCommand command, IEnumerable<SqlParameter> sqlParameters = new[]{}) =>
        ExecuteNonQuery(_connStr, command, sqlParameters);
    public static int ExecuteNonQuery(string connectionString, SqlCommand command, IEnumerable<SqlParameter> sqlParameters = new[]{}) =>
        ExecuteCommand(connectionString, command, cmd => cmd.ExecuteNonQuery());

    public T ExecuteScalar(SqlCommand command, IEnumerable<SqlParameter> sqlParameters = new[]{}) =>
        ExecuteScalar(_connStr, command, sqlParameters);
    public static T ExecuteScalar(string connectionString, SqlCommand command, IEnumerable<SqlParameter> sqlParameters = new[]{}) =>
        ExecuteCommand(connectionString, command, cmd => ConvertSqlCommandResult(cmd.ExecuteScalar()));

    public DataTable ExecuteToDataTable(SqlCommand command, IEnumerable<SqlParameter> sqlParameters = new[]{}) =>
        ExecuteToDataTable(_connStr, command, sqlParameters);
    public static DataTable ExecuteToDataTable(string connectionString, SqlCommand command, IEnumerable<SqlParameter> sqlParameters = new[]{}) =>
        ExecuteCommand(connectionString, command, cmd => PopulateDataTable(cmd));


    private static T ExecuteCommand<T>(string connectionString, SqlCommand command, IEnumerable<SqlParameter> sqlParameters, Func<SqlCommand, T> resultRetriever)
    {
        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            command.Parameters.AddRange(sqlParameters);
            command.Connection = connection;
            command.Connection.Open();
            return resultRetriver(command);
        }
    }

    private static DataTable PopulateDataTable(SqlCommand command)
    {
        var da = SqlDataAdapter(command);
        var dt = new DataTable();
        da.Fill(dt);
        return dt;
    }

    private static T ConvertSqlCommandResult(object result)
    {
        if (Convert.IsDbNull(result))
            return default(T); 
        if (result is T)
            return result as T;
        (T)Convert.ChangeType(result, typeof(T));
    }

}   

注意:在您的代码中,您包含了与获取特定任务有关的逻辑。 这应该与您的通用数据库逻辑保持分开(即,假设您要返回各种查询的数据表,而不必每次都重写GetDT代码)。 因此,我在下面提供了其他示例代码,展示了如何将逻辑分离到另一个类中。

public class TaskRepository //: IRepository<Task>
{
    ISqlDatabaseThing db;
    public TaskRepository(ISqlDatabaseThing db)
    {
        this.db = db;
    }

    readonly string GetByIdCommand = "select id, userid, name from tasks where id = @id";
    readonly string GetByIdCommandParameterId = "@id"
    readonly SqlDbType GetByIdCommandParameterIdType = SqlDbType.BigInt;
    public Task GetById(long id)
    {
        var command = new SqlCommand(GetByIdCommand);
        var parameters = IEnumerableHelper.ToEnumerable<SqlParameter>(new SqlParameter(GetByIdCommandIdParameter, GetByIdCommandIdParameterType, id));
        var dataTable = db.ExecuteToDataTable(command, parameters);
        return DataTableToTask(dataTable)[0];
    }
    private IEnumerable<Task> DataTableToTask(DataTable dt)
    {
        foreach (var row in dt.Rows)
        {
            yield return DataRowToTask(row);
        }
    }
    private Task DataRowToTask (DataRow dr)
    {
        return new Task()
        {
            Id = dr["Id"]
            ,Name = dr["Name"]
            ,UserId = dr["UserId"]
        };
    }

}

public static class IEnumerableHelper
{
    public static IEnumerable<T> ToEnumerable<T>(params T[] parameters)
    {
        return parameters;
    } 
}

注意:此代码未经测试; 任何问题,请让我知道。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM