Как обойти плохую схему базы данных? - PullRequest
4 голосов
/ 05 октября 2009

Нашу команду попросили написать веб-интерфейс для существующего бэкэнда SQL Server, который имеет свои корни в Access.

Одним из требований / ограничений является то, что мы должны ограничить изменения в SQL-интерфейсе. Мы можем создавать представления и хранимые процедуры, но нас попросили оставить таблицы / столбцы как есть.

Бэкэнд SQL не идеален. Большинство отношений являются неявными из-за отсутствия внешних ключей. В некоторых таблицах отсутствуют первичные ключи. Имена таблиц и столбцов противоречивы и включают такие символы, как пробелы, косые черты и знаки фунта.

Кроме того, чтобы получить новую работу или попросить пересмотреть это требование, может ли кто-нибудь предоставить какие-либо хорошие схемы для устранения этого недостатка?

ПРИМЕЧАНИЕ. Мы будем использовать SQL Server 2005 и ASP.NET с .NET Framework 3.5.

Ответы [ 11 ]

8 голосов
/ 05 октября 2009

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

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

Даже при наличии уровня доступа к данным основные проблемы в базе данных, такие как упомянутые вами ключи / индексы, будут вызывать проблемы при попытке масштабирования.

6 голосов
/ 05 октября 2009

Легко: убедитесь, что у вас есть надежные слои доступа к данным и бизнес-логики. Вы должны избегать искушения программировать непосредственно в базу данных из ваших кодов ASPX!

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

Вот несколько советов, которые помогут процессу:

Сначала исследуйте класс ObjectDataSource. Это позволит вам создать надежный BLL, который все еще может передавать элементы управления, такие как GridView, без использования прямого SQL. Они выглядят так:

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" 
    OldValuesParameterFormatString="original_{0}" 
    SelectMethod="GetArticles"   <-- The name of the method in your BLL class 
    OnObjectCreating="OnObjectCreating"   <-- Needed to provide an instance whose constructor takes arguments (see below)
    TypeName="MotivationBusinessModel.ContentPagesLogic">  <-- The BLL Class
    <SelectParameters>
        <asp:SessionParameter DefaultValue="News" Name="category" <-- Pass parameters to the method
            SessionField="CurPageCategory" Type="String" />
    </SelectParameters>
</asp:ObjectDataSource>

Если для создания экземпляра вашего класса BLL требуется передать аргументы, вам потребуется ссылка OnObjectCreating. В своем коде реализовайте это следующим образом:

    public void OnObjectCreating(object sender, ObjectDataSourceEventArgs e)
    {
        e.ObjectInstance = new ContentPagesLogic(sessionObj);
    }

Далее, реализация BLL требует еще нескольких вещей, которые избавят вас от проблем с поиском в Google. Вот реализация, которая соответствует вызовам выше.

namespace MotivationBusinessModel   <-- My business model namespace
{
    public class ContentPagesItem  <-- The class that "stands in" for a table/query - a List of these is returned after I pull the corresponding records from the db
    {
        public int UID { get; set; }
        public string Title { get; set; }  <-- My DAL requires properties but they're a good idea anyway
        ....etc...
    }

    [DataObject]  <-- Needed to makes this class pop up when you are looking up a data source from a GridView, etc.
    public class ContentPagesLogic : BusinessLogic
    {
        public ContentPagesLogic(SessionClass inSessionObj) : base(inSessionObj)
        {
        }

        [DataObjectMethodAttribute(DataObjectMethodType.Select, true)]  <-- Needed to make this *function* pop up as a data source
        public List<ContentPagesItem> GetArticles(string category)  <-- Note the use of a generic list - which is iEnumerable
        {
            using (BSDIQuery qry = new BSDIQuery())  <-- My DAL - just for perspective
            {
                return
                    qry.Command("Select UID, Title, Content From ContentLinks ")
                        .Where("Category", category)
                        .OrderBy("Title")
                        .ReturnList<ContentPagesItem>();
                 // ^-- This is a simple table query but it could be any type of join, View or sproc call. 
            }
        }
     }
 }

Во-вторых, легко добавить библиотеки DAL / BLL в ваш проект в качестве дополнительных проектов, а затем добавить ссылку на основной веб-проект. Это не только дает вашим DAL и BLL их собственные идентификационные данные, но и делает тестирование модулей несложным.

В-третьих, я почти не хочу это признавать, но это может быть одним из мест, где Microsoft Entity Framework пригодится. Обычно я не люблю Linq to Entities, но он разрешает спецификацию на стороне кода для отношений данных, которых вам не хватает в вашей базе данных.

Наконец, я понимаю, почему меняет на вашу структуру базы данных (например, перемещает поля вокруг), было бы проблемой, но добавление новых ограничений (особенно индексов) не должно быть. Они боятся, что внешний ключ приведет к ошибкам в другом программном обеспечении? Если так ... разве это не хорошо? тебе нужно немного болеть, чтобы знать, где лежит болезнь, нет?

По крайней мере, вы должны настаивать на возможности добавлять индексы по мере необходимости из соображений производительности. Кроме того, я согласен с другими, что представления могут иметь большое значение для создания структуры более разумной. Однако, этого действительно недостаточно в долгосрочной перспективе. Итак ... продолжайте и создайте Views (хранимые процедуры тоже), но вы должны все еще избегать кодирования непосредственно в базу данных. В противном случае вы по-прежнему привязываете свою реализацию к схеме базы данных, и в будущем ее избежать будет сложнее, чем если вы изолируете взаимодействия db с DAL.

4 голосов
/ 05 октября 2009

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

Если вы все еще сбиты с толку и не можете сделать полный редизайн, подойдите к ним с компромиссом, где вы можете переименовать столбцы и таблицы, добавить PK, FK и индексы. Это не должно занимать много времени и очень поможет.

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

2 голосов
/ 05 октября 2009

Я бы сделал "обход", если бы столкнулся с этой проблемой. Скажите вашим боссам, что лучший способ справиться с этим - создать базу данных «отчетов», которая по сути является динамической копией оригинала. Вы должны создать сценарии или отдельное приложение для обработки данных, чтобы обновить базу данных отчетов с изменениями в оригинале и распространить изменения, внесенные в вашу базу данных, обратно в оригинал, а затем написать свой веб-интерфейс для связи только с вашей базой данных «отчетов».

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

2 голосов
/ 05 октября 2009

Поскольку вы заявили, что вам необходимо "ограничить" изменения в схеме базы данных, кажется, что вы можете добавить поле первичного ключа в те таблицы, в которых они отсутствуют. Предполагая, что существующие приложения не выполняют никаких операторов «SELECT * ...», это не должно нарушать существующий код. После того, как это будет сделано, создайте представления таблиц с единым подходом и настройте триггеры в представлении для операторов INSERT, UPDATE и DELETE. У него будет незначительное снижение производительности, но он позволит создать единый интерфейс с базой данных. И тогда любые новые таблицы, которые будут добавлены, должны соответствовать новому стандарту.

Очень хакерский способ справиться с этим, но в прошлом я использовал такой подход с ограниченным доступом для изменения существующей схемы.

1 голос
/ 05 октября 2009

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

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

По крайней мере, у вас не должно быть много объединений, поэтому ваш SQL должен быть простым.

1 голос
/ 05 октября 2009

Может ли кто-нибудь предоставить какие-либо хорошие шаблоны для устранения этого недостатка

Похоже, вам отказали в единственной возможности "устранить этот недостаток".

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

0 голосов
/ 05 октября 2009

Я много интегрирую данные с плохо спроектированными базами данных, и метод, который я использовал, заключается в использовании базы данных с перекрестными ссылками, которая находится рядом с исходным db; это позволяет мне сохранять представления, хранимые процедуры и код обслуживания в связанной базе данных, не затрагивая исходную схему. Единственное исключение, которое я делаю, касаясь исходной схемы, - это то, что я буду реализовывать индексы, если это необходимо; однако я стараюсь избегать этого, если это вообще возможно.

Прелесть этого метода в том, что вы можете изолировать новый код от старого кода и создавать представления, которые обращаются к неверным определениям сущностей, ошибкам именования и т. Д., Не нарушая другой код.

Stu

0 голосов
/ 05 октября 2009

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

Я бы порекомендовал вам разумно проводить рефакторинг, когда вы вносите другие изменения, но не проводите масштабный рефакторинг на БД, это приведет к ошибкам и / или создаст слишком много работы для тестирования.

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

0 голосов
/ 05 октября 2009

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

Я бы отнесся к этим представлениям, как к необработанным таблицам. Это то, чем должны манипулировать ваши хранимые процедуры или уровень доступа к данным, а не базовые таблицы.

С точки зрения обеспечения соблюдения правил целостности, я предпочитаю помещать это в слой доступа к данным в коде с минимальными проверками целостности на уровне базы данных. Если вы предпочитаете проверки целостности в базе данных, вам следует широко использовать sprocs для их принудительного применения.

И не стоит недооценивать возможность поиска новой работы; -)

...