Осуществление записей класса в C#


С самого начала позвольте мне заявить, что я работаю с некоторыми старыми технологиями. Я бы предпочел использовать основы сущности, но я должен использовать то, что клиент использует, если я хочу получить деньги.

Я преобразования некоторых старый код в VB6/VBA на языке C#. VB код, опирается на RecordSet, которые позволяют просматривать результаты запросов, а также произвольно вносить изменения в текущую строку.

Дублировать эту функциональность в C#, мне нужно воспользоваться SqlDataAdapter, DataSet/DataTable и SqlCommandBuilder классов. Поскольку каждый объект базы данных, кажется, реализовать IDisposable, все это становится немного громоздким и отвлекает от моей основной логики.

Поэтому я старался обеспечить такой же функционал в отдельный класс, который реализует IDisposable. Я хотел бы некоторую обратную связь на этом классе. Моя главная забота-если я ничего не упустил, что мог бы оставить кое-что не моется, но и любовь идеи о том, как я могу сделать код лучше.

Класс Набора Записей

public class RecordSet : IDisposable
{
    protected SqlConnection Connection;
    protected bool OwnsConnection;
    protected SqlCommand Command;
    protected SqlDataAdapter Adapter;
    protected SqlCommandBuilder CommandBuilder;
    protected DataTable DataTable;

    protected int RowIndex;

    public RecordSet(string connectionString)
    {
        if (connectionString == null)
            throw new NullReferenceException("connectionString");
        Connection = new SqlConnection(connectionString);
        OwnsConnection = true;
    }

    public RecordSet(SqlConnection connection)
    {
        if (connection == null)
            throw new NullReferenceException("connection");
        Connection = connection;
        OwnsConnection = false;
    }

    ~RecordSet()
    {
        Debug.Assert(Connection == null);
        Debug.Assert(Command == null);
        Debug.Assert(Adapter == null);
        Debug.Assert(CommandBuilder == null);
        Debug.Assert(DataTable == null);
    }

    public void Open(string query, params SqlParameter[] parameters)
    {
        if (Disposed)
            throw new NotSupportedException("Cannot reuse RecordSet.");

        Command = new SqlCommand(query, Connection);
        if (parameters != null)
        {
            foreach (SqlParameter parameter in parameters)
                Command.Parameters.Add(parameter);
        }
        Adapter = new SqlDataAdapter(Command);
        CommandBuilder = new SqlCommandBuilder(Adapter);
        DataTable = new DataTable();

        Adapter.Fill(DataTable);
        RowIndex = -1;
    }

    public bool Read()
    {
        if ((RowIndex + 1) < DataTable.Rows.Count)
        {
            RowIndex++;
            return true;
        }
        return false;
    }

    public object this[string field]
    {
        get
        {
            return DataTable.Rows[RowIndex][field];
        }
        set
        {
            DataTable.Rows[RowIndex][field] = value;
        }
    }

    public void Update()
    {
        Adapter.Update(DataTable);
    }

    #region IDisposable

    protected bool Disposed = false;

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected void Dispose(bool disposing)
    {
        if (Disposed)
            return;

        if (disposing)
        {
            if (OwnsConnection && Connection != null)
                Connection.Dispose();
            if (Command != null)
                Command.Dispose();
            if (Adapter != null)
                Adapter.Dispose();
            if (CommandBuilder != null)
                CommandBuilder.Dispose();
            if (DataTable != null)
                DataTable.Dispose();
            Connection = null;
            Command = null;
            Adapter = null;
            CommandBuilder = null;
            DataTable = null;
        }
        Disposed = true;
    }

    #endregion
}

Пример Использования 1

string query = "SELECT * FROM TestTable WHERE Id = @FirstValue OR Id = @SecondValue";

using (RecordSet recordset = new RecordSet(connectionString))
{
    recordset.Open(query, new SqlParameter("@FirstValue", 2), new SqlParameter("@SecondValue", 3));
    while (recordset.Read())
    {
        recordset["Value3"] = 123;
    }

    recordset.Update();
}

Пример Использования 2

string query = "SELECT * FROM TestTable WHERE Id = @FirstValue OR Id = @SecondValue";

using (SqlConnection connection = new SqlConnection(connectionString))
using (RecordSet recordset = new RecordSet(connection))
{
    recordset.Open(query, new SqlParameter("@FirstValue", 4), new SqlParameter("@SecondValue", 5));
    while (recordset.Read())
    {
        recordset["Value3"] = 456;
    }

    recordset.Update();
}

Я с помощью SQL сервера. Спасибо за любые советы.



535
3
задан 19 марта 2018 в 03:03 Источник Поделиться
Комментарии
1 ответ

В конструкторах

public RecordSet(string connectionString)
{
if (connectionString == null)
throw new NullReferenceException("connectionString");
Connection = new SqlConnection(connectionString);
OwnsConnection = true;
}

public RecordSet(SqlConnection connection)
{
if (connection == null)
throw new NullReferenceException("connection");
Connection = connection;
OwnsConnection = false;
}

Я бы не бросить NullReferenceException но ArgumentNullException. Из документов


За исключение NullReferenceException при попытке получить доступ к члену типа, значение которого равно null.

против


Исключение ArgumentNullException, когда метод вызывается, и хотя бы один из переданных аргументов является null, но никогда не должно быть null.

Что заставляет меня задаться вопросом, что должно произойти, если connectionString это пустое или пустое пространство.


Это выглядит странно для меня как читателя кода

public void Open(string query, params SqlParameter[] parameters)
{
if (Disposed)
throw new NotSupportedException("Cannot reuse RecordSet.");

Если не утилизировать RecordSet это выглядит ОК, чтобы использовать другой запрос и повторное использование объекта. Если вы хотите заявить, что объект удален, вы должны бросить ObjectDisposedException но вы должны бросить его, а также от каждой public метод/свойство.


CommandBuilder не используется, так что вы могли бы просто удалить его.


Classlevel переменные должны быть названы с использованием camelCase корпус. PascalCase корпус должен быть использован для пространств имен, классов, свойств и методов.


Я хотел бы призвать вас всегда использовать фигурные скобки {} хотя они могут быть необязательными. Его немного больше, чтобы тип, но код выглядит более структурированным и Имо легче читать. Кроме того, он помогает предотвратить скрытые и поэтому трудно найти ошибки.

Если вы хотите придерживаться их не используете, это ваше решение, по крайней мере вы последовательны в своем стиле.

1
ответ дан 19 марта 2018 в 04:03 Источник Поделиться