Примеры дизайна C # OO для доступа к данным - PullRequest
1 голос
/ 15 ноября 2010

Я использую MS Enterprise Library 5.0 (блоки доступа к данным) для основного уровня данных моего приложения.

Хотя я понимаю основы ОО (да, мне нужно продолжать учиться - постоянно!)Я пытаюсь понять, где / почему / как использовать хороший дизайн, т. Е. Не обязательно повторять код и т. Д., А также все еще стараюсь сделать код простым для чтения и, конечно, отладкой.

Итак, во-первых, у меня есть следующий класс и метод по умолчанию / пример: (ps: возвращаемое значение из db / proc - XML)

public class ajaxget
{
    public enum outputType : int { JSON = 0, XML = 1 }

    public static string getMemberContacts(string sStartsWith, string sEndswith, outputType eOT)
    {
        //  Get the associated members based upon the criteria
        Database db = DatabaseFactory.CreateDatabase("MyDatabase");
        DbCommand cmd = db.GetStoredProcCommand("get_memberContactsXML");
        db.AddInParameter(cmd, "@memberID", DbType.Int64, Convert.ToInt64(sID));
        db.AddInParameter(cmd, "@startsWith1", DbType.String, sStartsWith);
        db.AddInParameter(cmd, "@startsWith2", DbType.String, sEndswith);
        IDataReader dr = db.ExecuteReader(cmd);
        StringBuilder sb = new StringBuilder();
        while (dr.Read())
        {
            sb.Append(dr.GetValue(0));
        }

        //  Clean up
        dr.Close();
        dr.Dispose();
        cmd.Dispose();

        //  What format to return?
        if (eOT == outputType.XML)
        {
            return sb.ToString();
        }
        if (eOT == outputType.JSON)
        {
            XmlDocument xdoc = new XmlDocument();
            xdoc.LoadXml(sb.ToString());
            return JsonConvert.SerializeXmlNode(xdoc);
        }
    }
}

Итак ... пока довольно просто.Я просто пытаюсь создать здесь шаблон того, как мне следует продолжить, скажем, больше методов "getMemberContacts" .. т.е. я должен создать общий метод "get", который является виртуальным методом, и переопределить параметры?Я знаю, это звучит очень корректно, и это так!я думаю, что это часть обучения.

Итак, в общем, я пытаюсь, конечно, повторно использовать метод "get", где имя params / proc явно отличается, однако фактическое возвращаемое значение (XML в этомв этом случае отсюда следует, что часть while / append, которая объединяет возвращаемые блоки XML), должна быть такой же, т. е. там, где возврат может быть оставлен как XML или, если он указан, может быть возвращен JSON.

Я понимаю, что этобазовый материал / концепция, но любые указания / идеи будут с благодарностью приняты!

Дэвид.

--- EDIT ---

Просто чтобы показать XML-часть SQL 2008, так как мне любопытно, что я не возвращаю XML прямо из SQL - снова яв целом понимаю, что получение необработанных данных для их использования по-разному - это хорошо, но в моем случае вся моя интерфейсная среда использует либо XML, либо JSON (JS Framework, к примеру, www.dhtmlx.com, который имеетбыло потрясающе).

Таким образом, процесс от SQL 2008:

CREATE PROCEDURE [dbo].[get_messagesForMemberXMLByID]
    @memberID as bigint=null,
    @days as int=-7
AS
BEGIN
    SET NOCOUNT ON;

    /* Setup the starting point (in the past) from when we wish to select the messages */
    Declare @startDate datetime
    set @startDate = DateAdd(d,@days, getdate())

    SELECT inboxID as "@id", convert(varchar(12),messageCreated,13) as messageCreated, convert(varchar(8), messageCreated,108) as messageCreatedTime, subject,message, messageOpened, messageFrom, messageFromID
    FROM bizzbox
    WHERE memberID = @memberID
    AND convert(char(8), messageCreated, 112) BETWEEN convert(char(8), @startDate,112) AND convert(char(8), getdate(), 112)
    ORDER BY messageCreated desc
    FOR XML PATH('row'), ROOT('rows')
END

, который выводит как:

<rows>
  <row id="1">
    <messageCreated>31 Oct 2010 </messageCreated>
    <messageCreatedTime>21:27:32</messageCreatedTime>
    <subject>Testing 123</subject>
    <message>Wibble Bibble!</message>
    <messageFrom>David</messageFrom>
    <messageFromID>7</messageFromID>
  </row>
</rows>

.. именно так ямне нужны данные, отформатированные для моего интерфейса.

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

Еще раз спасибо за все введенные данные -это действительно очень ценится.

Ответы [ 2 ]

1 голос
/ 15 ноября 2010

Прежде всего, вам нужно использовать с использованием конструкции вместо того, чтобы вручную утилизировать вещи.Вы можете использовать конструкцию с использованием для всего, что реализует IDisposable:

StringBuilder sb = new StringBuilder(); 

using(DbCommand cmd = db.GetStoredProcCommand("get_memberContactsXML"))
{
    db.AddInParameter(cmd, "@memberID", DbType.Int64, Convert.ToInt64(sID)); 
    db.AddInParameter(cmd, "@startsWith1", DbType.String, sStartsWith); 
    db.AddInParameter(cmd, "@startsWith2", DbType.String, sEndswith); 
    using(IDataReader dr = db.ExecuteReader(cmd))
    { 
        while (dr.Read()) 
        { 
            sb.Append(dr.GetValue(0)); 
        } 
    }
}

Преимущество оператора using (помимо того, что оно является кратким, читаемым и в целом потрясающим), заключается в том, чторесурсы удаляются, даже если возникает исключение.В вашем примере исключение из вызова db.ExecuteReader (cmd) привело бы к тому, что команда не была удалена.

Шив Кумар также сделал несколько очень хороших замечаний.Я бы сделал что-то вроде этого:

public abstract class DataAccessLayerBase
{
    protected string GetXml(string storedProcedureName, OutputType outputType, params Tuple<string,DBType,object>[] parameters)
    {
        StringBuilder sb = new StringBuilder();

        //  Get the associated members based upon the criteria  
        Database db = DatabaseFactory.CreateDatabase("MyDatabase");  

        using(DbCommand cmd = db.GetStoredProcCommand(storedProcedureName))
        {
            foreach(var parameter in parameters)
            {
                db.AddInParameter(cmd, parameter.Item1, parameter.Item2, parameter.Item3);
            }

            using(IDataReader dr = db.ExecuteReader(cmd))
            {
                while (dr.Read())  
                {  
                    sb.Append(dr.GetValue(0));  
                }  
            }      

            switch(outputType)
            {
                case OutputType.Xml:
                    return sb.ToString();  
                case OutputType.Json:
                    XmlDocument xdoc = new XmlDocument();  
                    xdoc.LoadXml(sb.ToString());  
                    return JsonConvert.SerializeXmlNode(xdoc);  
                default:
                    throw new NotSupportedException(); // Some sort of error.
            }
        }
    } 
}

Затем просто создайте подкласс для каждой функциональной области:

public class MemberContactsDal : DataAccessLayerBase
{
    public string GetMemberContacts(long memberID, string startsWith, string endsWith, OutputType outputType)
    {
        // Call the method in the base class to handle all of the parsing.
        return GetXml(
            "get_memberContactsXML", 
            outputType, 
            new Tuple("@memberID", DBType.Int64, memberID ), 
            new Tuple("@startsWith1", DBType.String, startsWith), 
            new Tuple("@startsWith2", DBType.String, endsWith)
        );
    }
}

Звучит так, как будто в вашей жизни происходит что-то немного излишнее.хранимые процедуры, если они возвращают XML, хотя ...

Я надеюсь, что мой пример поможет.Я не пытался его скомпилировать, но это должно быть правильно.

1 голос
/ 15 ноября 2010

Это довольно сложный вопрос, и поэтому ответов на него будет много и он будет разным.Прежде всего, поскольку вы находитесь в фазе обучения ...

  1. Придерживайтесь соглашения C # для имен методов, параметров, переменных и тому подобного.И не используйте венгерскую нотацию, если вам не нужно (есть некоторые крайние случаи, когда венгерская нотация может использоваться, но не там, где вы ее используете.
  2. При использовании Enum вместо оператора if используйте оператор Switch-else.
  3. также относится к соглашениям о присвоении имен, о которых говорилось выше, но я решил выделить это отдельно - значения Enum должны быть .Xml и .Json, а не XML и JSON.

У меня есть несколько вопросов: 1. Почему вы используете Xml? 2. Почему в вашей таблице базы данных, содержащей контакты участника, нет «полей», представляющих атрибуты контактов участника?

Ответитьодин из ваших вопросов о повторном использовании метода "get" ... Я бы не стал использовать отдельные методы для каждого метода get, потому что типы и количество параметров неизменно будут меняться. В этих методах могут быть общие функциональные возможности.как частный метод, который могут использовать все методы «get», но сам каждый метод должен быть отдельным. Это потому, что вы должны посмотреть накласс доступа к данным, имеющий открытый (или внутренний) API.То есть, если вы посмотрите на общедоступные методы этого класса, вы должны получить четкое представление о том, что может делать этот класс, и какие параметры ему требуются для этого.Наличие одного универсального метода не только заставит вас пройти через обручи, пытаясь вставить квадратный колышек в круглое отверстие, но, взглянув на ваши общедоступные методы, вы не поймете, какую функциональность он предоставляет.

Ваш методGetMemberContacts должен иметь следующую подпись

public static List<MemberContact> GetMemberContacts(int memberId)

Таким образом, чтобы получить контакты конкретного участника, этот идентификатор участника должен быть передан в качестве параметра.Скорее всего, этот метод должен вернуть список Membercontact или DataTabl / DataSet.

Если вам нужен Xml, бизнес-уровень может взять эти данные и преобразовать их в xml.Если вам нужно, вы можете использовать тот же список и преобразовать его в Json.Пусть бизнес-уровень решит или, что еще лучше, пусть у него есть 3 метода, которые возвращают контакты конкретного участника тремя различными способами (A List, Json, Xml).

Не уверен, что sStartWith и sEndWith есть в вашем коде.Это означает, что вам нужно лучшее имя метода и лучшие имена параметров, которые правильно указывают намерение.

...