web-dev-qa-db-ja.com

初心者のためのデータベースのベストプラクティス

したがって、私は非常に少量の実務経験を持つ大学生のComp Sci学位を目指すかなり新しいプログラマーです。私のプログラムのインターンシップタイプの仕事を探していると、私はいくつかの専門家から聞いた「データベースでの作業がすべての現代のコンピューターサイエンスの仕事の90%を占めている」ことに気づきました。しかし、私のプログラムは3年目まではデータベースを使ったコースを実際に持っていないので、少なくともこの間に自分自身でいくつかのことを学びたいと思っています。

私は、SOや、一般的に私のような誰かのためのインターネットについてはほとんど見たことがありません。データベースでデータを読み書きする方法のメカニズムに関するチュートリアルはたくさんあるようですが、ほとんど関連するベストプラクティスについて。私が話していることを実証し、実際の質問を乗り越えるのを助けるために、これは インターネットで簡単に見つけることができます

public static void Main ()
{
    using (var conn = new OdbcConnection())
    {
        var command = new OdbcCommand();
        command.Connection = conn;
        command.CommandText = "SELECT * FROM Customer WHERE id = 1";
        var dbAdapter = new OdbcDataAdapter();
        dbAdapter.SelectCommand = command;
        var results = new DataTable();
        dbAdapter.Fill(results);
    }

    // then you would do something like
    string customerName = (string) results.Rows[0]["name"]; 
}

などなど。これは非常に簡単に理解できますが、明らかに問題でいっぱいです。私はこのようなコードから始めて、「SQLをあちこちに配置するのは馬鹿げているようです。これらすべてを定数ファイルに入れる必要があります」のようなことをすぐに言い始めました。そして、同じコード行をいたるところに配置して、接続オブジェクトなどをすべてメソッド内に配置するのはばかげていることに気づきました。

public DataTable GetTableFromDB (string sql)
{
    // code similar to first sample
}    

string getCustomerSql = String.Format(Constants.SelectAllFromCustomer, customerId);
DataTable customer = GetTableFromDB(getCustomerSql);
string customerName = (string) customer.Rows[0]["name"];

これは大きな改善のようです。たとえば、OdbcConnectionからSQLiteConnectionに変更するのは非常に簡単です。しかし、データにアクセスするその最後の行は、依然として扱いにくいように見えました。また、フィールド名を変更するのも( "name"から "CustName"などに変更するのは)苦痛です。 型付きデータセットまたはカスタムビジネスオブジェクトを使用する について読み始めました。私はまだすべての用語に少し混乱していますが、 とにかく調査する]と決定しました。 光沢のあるデータベースに依存するのは愚かだと思いますWizard to何が起こっているのか、そしてその理由を実際に知る前に、(リンクされた記事のように)このすべてを私に代わって行うので、自分で試してみて、次のようなことを始めました:

public class Customer
{
    public string Name {get; set;}
    public int Id {get; set;}

    public void Populate ()
    {
        string getCustomerSql = String.Format(Constants.SelectAllFromCustomer, this.Id);
        DataTable customer = GetTableFromDB(getCustomerSql);
        this.Name = (string) customer.Rows[0]["name"]; 
    }

    public static IEnumerable<Customer> GetAll()
    {
        foreach ( ... ) { 
            // blah blah
            yield return customer;
        }
    }
}

醜いテーブルのものを隠して強力なタイピングを提供し、外部コードが次のようなことをできるようにします

var customer = new Customer(custId);
customer.Populate();
string customerName = customer.Name;

本当にいいです。そして、Customerテーブルが変更された場合、コードの変更は、Customerクラス内の1か所でのみ行う必要があります。

だから、このとりとめのないすべての終わりに、私の質問はこれです。データベースコードのゆっくりとした進化は正しい方向に進んでいますか?そして次にどこへ行くのですか?このスタイルはすべて小さめのデータベースに適していますが、さまざまなテーブルが大量にある場合、それぞれのクラスすべてを書き出すのは面倒です。この種のコードを生成できるソフトウェアについて聞いたことがありますが、それでもDAL/ORM/LINQ2SQL/etc専門用語に戸惑っており、それらの巨大なソフトウェアは圧倒的です。私は正しい方向に向けることができる、圧倒的に複雑ではない優れたリソースを探しています。このトピックについて私が見つけることができるのは、頭の中で複雑な記事、またはVisual Studioなどでポイントアンドクリックウィザードを使用する方法を示す記事だけです。また、データベースの設計/正規化に関する情報ではなく、コードでのデータベースの操作に関する情報を探していることにも注意してください。そこには多くの優れた資料があります。

このテキストの巨大な壁を読んでくれてありがとう。

44
jloubert

確かに非常に良い質問であり、あなたは確かに正しい軌道に乗っています!

私自身、コンピューターエンジニアであること、データベース、およびデータベースと対話するためのコードの記述方法も、私の大学の学位の大きな部分ではありませんでした。

これが私の経験です。あるプロジェクトでは90年代前半のレガシーテクノロジーを使用し、別のプロジェクトではC#とWPFを使用した最新のテクノロジーを使用しています。

用語を説明するために最善を尽くしますが、私自身はまだ専門家ではありません。

テーブル、オブジェクト、およびマッピングOh My!

データベースにはテーブルが含まれていますが、実際には何ですか?これは、他のフラットデータに関連するフラットデータであり、急いで取得を開始すると、すぐに乱雑になります。文字列はあちこちに配置され、SQLステートメントは繰り返され、レコードは2回ロードされます。したがって、一般に、各テーブルレコード(またはそれらの関係に応じてテーブルレコードのコレクション)を単一のオブジェクトとして表すことをお勧めします。モデルとして。これは、データをカプセル化し、その状態を維持および更新するための機能を提供するのに役立ちます。

投稿では、Customerクラスがモデルとして機能します。ですから、すでにその利点を理解していることになります。

これで、すべてのモデルコードを書き込むさまざまなツール/フレームワーク(LINQ2SQL、dotConnect、Mindscape LightSpeed)が用意されました。最終的には、オブジェクトをリレーショナルテーブルにマッピングしたり、O/Rマッピングを参照したりします。

予想通り、データベースが変更されると、O/Rマッピングも変更されます。先ほど触れたように、お客様が変わった場合、1か所で修正する必要があります。これも、クラスに配置する理由です。私のレガシープロジェクトの場合、モデルの更新はモデルが多すぎるために多くの時間を消費しましたが、新しいプロジェクトでは数回クリックするだけですが、最終的に結果は同じです。

誰が何を知っている必要がありますか?

私の2つのプロジェクトでは、オブジェクトがテーブルと対話する方法が2つありました。

一部のキャンプでは、モデルはテーブルに関するすべてを知っている必要があり、モデルを保存する方法、接続/セッションへの直接共有アクセス権を持ち、Customer.Delete()Customer.Save()などのアクションをすべて自分で実行できます。

他のキャンプでは、読み取り、書き込み、削除、ロジックを管理クラスに配置します。たとえば、MySessionManager.Save( myCustomer )などです。この方法には、オブジェクトに変更の追跡を簡単に実装でき、すべてのオブジェクトが同じ基になるテーブルレコードを参照できるという利点があります。ただし、それを実装することは、前述のローカライズされたクラス/テーブルロジックのメソッドよりも複雑です。

結論

あなたは正しい軌道に乗っていて、私の意見ではデータベースとのやり取りは非常にやりがいがあります。自分で研究を始めたときの頭の回転を覚えています。

少し実験して、小さなプロジェクト、おそらくシンプルな請求システムを開始して、自分でモデルを作成してみることをお勧めします。その後、別の小さなプロジェクトを試して、データベースO/Rマッピングツールを活用して違いを確認してください。

18
Matthew

あなたの進化は間違いなく正しい方向にあります。考慮すべきいくつかの追加事項:

8
Corbin March

データベースについて学びたいのであれば、最初のステップはプログラミング言語を忘れ、次に、どのデータベースを使用しているかを忘れてSQLを学ぶことです。確かに、mySQL、MS SQLserver、Oracleの間には多くの違いがありますが、同じことがたくさんあります。

結合、選択形式、日付形式、正規化について学びます。何百万ものレコードがあり、物事が遅くなり始めたときに何が起こるかを学び、それを修正することを学びます。

たとえば自転車屋など、興味のあるものに関連するテストプロジェクトを作成します。数百万の製品と数百万の顧客を追加するとどうなるかを見て、データを関連付ける必要があるすべての方法を考えてください。

サーバーにソースコードをアップロードするよりもはるかに高速であるため、ローカルデータベース(続編プロ、mysqlワークベンチなど)でクエリを実行するにはデスクトップアプリを使用します。そしてそれを楽しんでください!

3
direct00

私見、あなたは間違いなく正しい方向に進んでいて、メンテナンス可能なコードを使って作業するのは本当に素晴らしいです!ただし、このアプローチが実際のアプリに拡張できるとは思いません。役立つかもしれないいくつかの考え

  1. 作成しているコードは、操作が非常に簡単で、メンテナンスも簡単ですが、事前に多くの作業が必要になるため、ウィザードが非常に人気がある理由の1つです。これらは作業するのに最適なものではありませんが、多くの時間を節約できます。
  2. データベースからのクエリはほんの始まりにすぎません。型指定されたデータセットとウィザードを一般的に使用するもう1つの理由は、ほとんどのアプリケーションで、ユーザーが何らかの段階で情報を編集し、更新のために送り返すためです。単一のレコードで問題ありませんが、データが4つの深さのテーブルの階層を持つ正規化された方法で最もよく表現されている場合はどうでしょうか。呼び出しがすべて地獄のように動作するように、更新/挿入/削除ステートメントを手動で自動生成するコードを作成するため、ツールが唯一の方法です。型指定されたDataSetは、これらの更新を実行するためのすべてのコードを生成し、切断された(クライアント側など)更新/最近の変更のロールバックを処理するためのいくつかの非常に強力な機能を備えています。
  3. 最後の連中がSQLインジェクション(業界で重大な問題)について述べたこと、そして DBCommand オブジェクトを使用してDbParametersを追加することで身を守ること。

一般に、コードからデータベースへの移行には、 インピーダンスミスマッチ と呼ばれる非常に大きな問題があります。ギャップを埋めるのは非常にトリッキーであり、それが業界の大多数がツールを頼りにして重労働を行っている理由です。私のアドバイスは、ウィザードを試すことです-ウィザードをステップ実行することはスキルのテストではありませんが、すべての欠点/バグおよびそれらのさまざまな回避策を学ぶことは、業界で本当に役立つスキルであり、いくつかのより高度なものに到達することができますデータ管理のシナリオ(たとえば、前述の4階層のテーブル階層の切断された更新)。

2
Tom Carver

Linq to SQLやEntity Frameworkなどが少し怖い場合は、途中まで足を踏み入れて、iBATIS.NETのようなものを探索できます。これは、データベース接続管理の苦痛を取り、結果セットをカスタムドメインオブジェクトにマッピングする、単なるデータマッパーツールです。

すべてのオブジェクトクラスとSQLを記述する必要がありますが、リフレクションを使用してすべてのデータをクラスにマップします。また、基礎となる接続のすべてを心配する必要はありません(簡単にツールを記述できます)クラスを生成します)。 iBATISを起動して実行すると(興味があると想定して)、コードは次のようになります。

var customer = Helpers.Customers.SelectByCustomerID(1);

そのSelectByCustomerID関数はCustomersマッパー内に存在し、その定義は次のようになります。

public Customer SelectByCustomerID(int id)
{
    Return Mapper.QueryForObject<Customer>("Customers.SelectByID", id);
}

「Customers.SelectByID」はXMLステートメント定義にマップされます。「Customers」はネームスペース、「SelectByID」はSQLを含むマップのIDです。

<statements>
    <select id="SelectByID" parameterClass="int" resultClass="Customer">
        SELECT * FROM Customers WHERE ID = #value#
    </select>
</statements>

または、顧客を変更したい場合は、次のようなことができます。

customer.FirstName = "George"
customer.LastName = "Costanza"

Helpers.Customers.Update(customer);

LINQ to SQLとEntity Frameworkは、SQLを自動的に生成することにより、より洗練されています。 SQLと自分のドメインオブジェクトの外観を完全に制御できるため、iBATISが好きです。

iBATISをチェックしてください (MyBatis.NETという名前でGoogleに移行されました)。別の優れたパッケージは NHibernate です。これは、iBATISよりも数歩進んでおり、完全なORMに近いものです。

2
Cᴏʀʏ