4

これは私の最初の投稿です、うまくいけば私はルールに従っています!

レンガの壁に頭をぶつけて数週間、インターネットで何時間も検索した後、私は自分の投稿を作成し、すべての専門家からの回答とガイダンスを見つける必要があると判断しました。

SQL2008データベースとEntityFramework4を使用して2つの部分を結合するASP.NETアプリケーション(Visual Studio 2010)を構築しています。最初にデータベースをデータベースプロジェクトとして設計し、次にエンティティモデルをクラスプロジェクトとして構築しました。このクラスプロジェクトは、メインのASP.NETプロジェクトで参照されます。これは、エンティティフレームワークの用語でデータベースファーストと呼ばれていると思いますか?

私はWebアプリ(主にWinFormsアプリを開発しています)にかなり慣れていません。これは、エンティティフレームワークを使用する最初の試みです。

私はC#をほぼ理解できるので、可能であれば、提供する可能性のあるコードサンプルまたはスニペットがVBで優先されます。

私がこれまでにどこにいるのかについての背景を説明します。register.aspxという登録ページを作成し、ASP:WizardとASP:TextBox、ASP:DropdownList、ASP:CheckBoxListを使用してウィザードスタイルのフォームを作成しました。これらはすべてHTMLテーブル内に配置され、一部の書式設定にCSSを使用しています。ユーザーがウィザードの最後のページを取得して[完了]を押すと、次のようにVBコードビハインドファイルでいくつかのコードを実行します。

Protected Sub wizardRegister_FinishButtonClick(sender As Object, e As System.Web.UI.WebControls.WizardNavigationEventArgs) Handles wizardRegister.FinishButtonClick
    Dim context As New CPMModel.CPMEntities
    Dim person As New CPMModel.Person
    Dim employee As New CPMModel.Employee

    Dim newID As Guid = Guid.NewGuid

    With person
        .ID = newID
        .UserID = txbx_UserName.Text
        .Title = ddl_Title.SelectedValue
        .FirstName = txbx_FirstName.Text
        .MiddleInitial = txbx_MiddleInitial.Text
        .FamilyName = txbx_FamilyName.Text
        .Gender = ddl_Gender.SelectedValue
        .DOB = txbx_DOB.Text
        .RegistrationDate = Date.Now
        .RegistrationMethod = "W"
        .ContactMethodID = New Guid(ddl_ContactMethodList.SelectedValue)
        .UserName = txbx_UserName.Text
        If Not (My.Settings.AuthenticationUsingAD) Then
            .Password = txbx_Password.Text ' [todo] write call to salted password hash function
        End If
        .IsRedundant = False
        .IsLocked = False
    End With

    context.AddToPeople(person)

    With employee
        .ID = newID
        .PayrollNumber = txbx_PayrollNumber.Text
        .JobTitle = txbx_JobTitle.Text
        .DepartmentID = ddl_DepartmentList.SelectedValue
        .OfficeNumber = txbx_OfficeNumber.Text
        .HomeNumber = txbx_HomeNumber.Text
        .MobileNumber = txbx_MobileNumber.Text
        .BleepNumber = txbx_BleepNumber.Text
        .OfficeEmail = txbx_OfficeEmail.Text
        .HomeEmail = txbx_HomeEmail.Text
        .IsRedundant = False
        .RedundantDate = Nothing

         '--------------------------
        .FiledBy = Threading.Thread.CurrentPrincipal.Identity.Name
        .FiledLocation = My.Computer.Name
        .FiledDateTimeStamp = Date.Now
        '----------------------------
    End With

    context.AddToEmployees(employee)
    context.SaveChanges()
End Sub

上記は正常に機能し、それを行うための賢明な方法のようであり(Entity Frameworkを初めて使用することを思い出してください)、期待した結果が得られました。

このページにはmanage.aspxという別のページがあります。これはタブコントロールです。各タブページには、asp:EntityDataSourceにバインドされたasp:DetailsViewが含まれています。すべてのエンティティデータソースで更新を有効にし、一部のページでも有効にしました。挿入します。削除が有効になっているものはありません。

この段階でアプリをビルドして実行すると、すべてが正常に機能します。[編集]リンクを押して変更を加え、[更新]を押すと、それらの更新が画面にすぐに表示され、データベースに正しい値が表示されます。 。

ここに問題があります。上記のコード(太字)の更新をインターセプトする必要があります。データベースにFiledBy、FiledLocation、およびFiledDateTimeStampという列があることに注意してください。ASP.NETページを表示しているユーザーにこれらの列を表示したくありませんが、ユーザーが更新を押したときにそれらを更新したいと思います(変更があった場合)。ASP:DetailsViewをテンプレートに変換してから、次のようなものでHTML側をコーディングしてみました。

<@# Eval(User.Name) #>

編集モードのときにテキストボックスに正しい値を入れることができましたが、次の問題がありました。

  1. データベースに保存されませんでした
  2. やりたくないテキストボックスを表示する必要があります

エンティティフレームワークモデルのSaveChanges部分をオーバーライドできる、ここや他のWebサイトの他のいくつかの投稿を読みました。この一例は、以下のコードにあります。

public override int SaveChanges() 
{
var entities = ChangeTracker.Entries<YourEntityType>() 
                            .Where(e => e.State == EntityState.Added) 
                            .Select(e => e.Entity); 
var currentDate = DateTime.Now; 
foreach(var entity in entities) 
{ 
    entity.Date = currentDate; 
} 

return base.SaveChanges(); 
} 

問題は、私がそのアイデアを理解し、それをVBに変換することはできるが、これをどのように実装するかがわからないということです。コードはどこに置きますか?コードを呼び出すにはどうすればよいですか?等

理想的には、次の要件を満たすソリューションを見つけたいと思います。

  • エンティティモデルを再生成/更新しても上書きされません
  • モデル内のすべてのテーブルにコピーして貼り付ける必要はありません(すべてではありませんが、ほとんどのテーブルに監査列があります)
  • 他の列に使用できます。たとえば、ユーザーがチェックリストで選択を行った場合、別の(ユーザーに公開されていない)列に値を書き込みたい場合があります。

5月のWebページにデータを表示するための正しいアプローチを取っていますか?確かにDataViewとGridViewには制限があります。テーブルタグに登録フォームのようなフォームを作成することを考えましたが、テキストボックスなどにデータベースの値を入力する方法がわかりません。また、多くのテーブルには1対多の関係があるため、ページングを実装する方法もありませんが、テーブルにテキストボックスを入力すると、変更を保存するのは簡単です。

皆様のご支援をよろしくお願い申し上げます。

ケビン。

さて、私は近づきましたが、それでも正しく機能していません。次のコードを使用して、DataboundイベントのDetailsViewの値を編集しました。正しいタイムスタンプを読み取り専用テキストボックスに書き込みますが、DetailsViewコントロールの[更新]ボタンを押したときにこの値をデータベースに正しく戻さない場合。

Protected Sub dv_Employee_DataBound(sender As Object, e As EventArgs) Handles dv_Employee.DataBound
    If dv_Employee.CurrentMode = DetailsViewMode.Edit Then
        For Each row In dv_Employee.Rows
            If row.Cells(0).Text = "FiledDateTimeStamp" Then
                row.Cells(1).Text = Date.Now()
            End If
        Next
    End If
End Sub
4

2 に答える 2

1

変更の保存方法をオーバーライドするというアイデアが好きです。コンテキストは部分クラスである必要があるため、同じ名前空間で同じ名前の部分としてマークされた別のクラスを定義し、それにオーバーライドを追加する必要があります。

Namespace CPMModel
  Partial Public Class CPMEntities
   ...Your override here
End Class

これはデフォルトのSaveChangesメソッドのオーバーライドであるため、呼び出し方法を変更する必要はありません。エンティティレベルのプロパティにアクセスする方法を見つける必要があります。

これはすべてのエンティティの変更をコミットするメソッドであるため、エンティティクラスは具体的なプロパティを定義しないため、例のようにプロパティにアクセスすることはできません。したがって、エンティティの部分的なクラスを作成し、それらすべてに、対話するプロパティを定義するインターフェイスを実装させる必要があります。

インターフェイスを作成します。

Interface IDate
   Property Date() as DateTime
End Interface

IDateインターフェイスを実装するエンティティごとに部分クラスを作成します。(これらの部分クラスには同じルールが適用され、部分としてマークされ、拡張するクラスと同じ名前を持ち、同じ名前空間に存在する必要があります)次に、SaveChangesオーバーライドで

public override int SaveChanges() 
{
         var entities = ChangeTracker.Entries<Entity>() 
                        .Where(e => e.State == EntityState.Added) 
                        .Select(e => e.Entity); 
        var currentDate = DateTime.Now; 
        foreach(var entity in entities) 
        { 
                ***Now cast entity to type of IDate and set your value ***
                entity.Date = currentDate; 
        } 

        return base.SaveChanges(); 
} 

私はVbで記述しないので、構文はC#のままにしました。

それはあなたのすべての要件を満たすはずです。

于 2012-10-22T15:59:13.170 に答える
0

さて、これは私がそれが機能することを想像した方法ではありませんが、実際には私のニーズを満たしています。すこし!

私がしたことは、aspxファイルのコードビハインドファイルに保護されたサブを書き込むことでした。

Protected Sub CustomEntityUpdate_Employee(sender As Object, e As  
EntityDataSourceChangingEventArgs)
    Dim emp As CPMModel.Employee = e.Entity
    ' Check if the entity state is modified and update auditing columns
    If emp.EntityState = EntityState.Modified Then
        emp.FiledDateTimeStamp = Date.Now()
        emp.FiledBy = Threading.Thread.CurrentPrincipal.Identity.Name
        emp.FiledLocation = My.Computer.Name
    End If
End Sub

次に、aspxページで、エンティティデータソースコードを編集して、上記のサブルーチンを呼び出しました。

#nUpdating="CustomEntityUpdate_Employee"

<asp:EntityDataSource 
    ID="eds_Employee" 
    runat="server" 
    ConnectionString="name=CPMEntities" 
    DefaultContainerName="CPMEntities" 
    EnableFlattening="False" 
    EnableUpdate="True" 
    EntitySetName="Employees" 
    AutoGenerateWhereClause="True" 
    Where="" 
    EntityTypeFilter="Employee" 
    **OnUpdating="CustomEntityUpdate_Employee">**
    <WhereParameters>
        <asp:SessionParameter 
            Name="ID" 
            SessionField="UserID" />
    </WhereParameters>
</asp:EntityDataSource>

Protected Subは、エンティティが変更されているかどうか、およびエンティティ監査列が必要な値で更新されているかどうかを確認します。

それは機能しますが、確かにもっと多くのコードが必要になります。理想的には、これをおそらくクラスにパッケージ化し、OnUpdatingイベントを介してさまざまなaspxページからsubを呼び出し、クラスにどのエンティティがあったかを把握させる方法が必要です。呼び出しを行い、そこですべてのロジックを処理します。

于 2012-10-21T02:49:12.330 に答える