2010-11-15 1 views
1

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

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

Так первый из летучей мыши, у меня есть следующий класс и по умолчанию/пример метода: (PS: возвращаемое значение из БД/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 может быть возвращен.

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

David.

--- EDIT ---

Просто, чтобы показать XML часть SQL 2008, как мне любопытно замечания о не возвращении XML прямо из SQL - снова я вообще понимаю, что получение исходных данных в использовать его по-разному - это хорошо, но в моем случае все мои интерфейсные фреймворки используют либо XML, либо JSON (инфраструктура JS, кстати, является 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> 

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

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

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

+0

S - Если ваш пользовательский интерфейс будет отображать этот Xml/Json напрямую, то я действительно не вижу проблемы с тем, что вы делаете. Лучше всего заставить его работать, а затем, если есть проблемы с производительностью, посмотрите на более традиционные подходы. Это также звучит так, будто нет бизнес-уровня, который будет выполнять операции над данными, поэтому почему бы не передать xml прямо? – sheikhjabootie

+0

Да, правда .. страница ASHX в этом случае могла бы сделать этот вызов напрямую. Однако в свете нескольких других проблем с дизайном, я думаю, что я вернусь к тому, чтобы BAL создавал XML/JSON. Несмотря на то, что это дополнительный шаг, имеет смысл разделить все функции, идущие вперёд. Еще раз спасибо за пример/комментарии !! –

ответ

1

Прежде всего, вам необходимо использовать с использованием конструкции вместо того, чтобы вручную утилизировать вещи. Вы можете использовать используя конструкции на что-нибудь, который реализует 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)); 
     } 
    } 
} 

Преимущества с помощью оператора (кроме сжатости, читаемых и вообще удивительного) является то, что он будет гарантировать, что ресурсы будут удаляться, даже если возникает исключение. В вашем примере исключение из вызова 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) 
     ); 
    } 
} 

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

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

+0

Эй, это отличный пример, на самом деле именно то, что я искал - по крайней мере, чтобы подтолкнуть меня в «правильном» направлении. Наверное, я был «старой школой» и не использовал «использование» заявления, «Я понимаю, что они уничтожают объекты, даже если возникает исключение, так что очень ценная информация. Что касается рассуждений о возврате XML из SQL, я опубликую здесь ответ (не отвечать, конечно, просто чтобы показать код проще) показать, что он делает - снова SQL 2008 h как хороший XML-движок, и казалось «быстрее» просто получить XML напрямую, если это все, что я собираюсь использовать? –

+0

На самом деле я не буду отвечать на свой вопрос .. просто добавит редактирование оригиналу (DOH!). Просто чтобы показать XML-часть SQL 2008, я понимаю, почему, как правило, вы должны абстрагировать построение XML от сырых данных - просто кажется, что очень важно получить прямой XML, если это все, что я использую (т. Е. За исключением библиотека JSON.NET для преобразования в JSON, если это необходимо). –

+0

Действительно .. Большое вам спасибо за помощь в этом. Вы открыли мне глаза на практический пример кортежей! наряду с отличным шаблоном/примером базового объекта. –

1

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

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

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

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

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

public static List<MemberContact> GetMemberContacts(int memberId) 

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

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

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

+0

Добавлен в мой ответ последние 5 абзацев –

+0

Эй, круто, спасибо за всеобъемлющий ответ. Я не венгерский, поэтому использование венгерской нотации - это не проблема :), но я понимаю, что вы имеете в виду! Причина, по которой я возвращал прямой XML из SQL, я предполагаю, что мое приложение (достаточно справедливое, я не хотел/не хотел создавать массивный документ, объясняющий слишком много), как правило, использует интерфейс JS framework, а не ASP.NET , и, как таковая, большинство моих интерфейсов полагаются непосредственно на XML - так что рассуждение заключалось в том, что SQL может предоставить мой XML напрямую, без необходимости делать какие-либо другие формы, тогда я думал, что это будет быстрее? –

+0

... Кроме того, я определенно соглашаюсь на стандарты именования и т. Д., А также использование Enums/switch и т. Д., Это сделает точно. Спасибо за ответ, определенно много, о чем нужно подумать. –