2017-06-30 6 views
0

Web APIベースのアプリケーションでマルチテナントアーキテクチャを実装しようとしています。私たちはSQL ServerでRLSを使用しており、Subscription_Idは各サブスクライバに与えられているものです。 SQL ServerではSubscription_Idの既定値を設定していますので、db.SaveChanges()を呼び出している間は、APIからSQL Serverに移動するSubscription_Idを無視したいだけです。
Subscription_Idの値をSaveChanges()のオーバーライド方法で設定しようとしましたが、ここで固まってしまいました。DbContext.SaveChanges()のエントリ値を変更する方法

public override int SaveChanges() 
{ 
    var objectType = selectedEntity.CurrentValues.ToObject(); 
    Guid value = new Guid("54E720FC-616B-44C6-8485-5F2185FD7B4C"); 
    PropertyInfo propertyInfo = 
    objectType.GetType().GetProperty("Subscription_Id"); 


    ChangeTracker.Entries().FirstOrDefault() 
     .CurrentValues.ToObject().GetType() 
     .GetProperty("Subscription_Id") 
     .SetValue(objectType, Convert.ChangeType(value, propertyInfo.PropertyType), null); 

    return base.SaveChanges(); 
} 
+0

なぜSubscription_Idを変更または上書きしたいのですか?それは私が考えるプライマリ/ユニークなキーです。 –

+0

サブスクリプションIDがないので、サブスクライバに関連するすべてのデータがサブスクライバIDとともに保存されます。 – Gunashekar

+0

savechanges()でsubscriptionIdの値を設定する理由は何ですか? –

答えて

0

私のアドバイスは、SaveChanges()コードを変更しないことです。

RLSを使用する推奨される方法は、TenantIdカラムをEFモデルとコードに対して透過的にすることです。エンティティにテナントIDまたはナビゲーションプロパティを定義する必要はありません。この方法でSaveChanges()コードを変更する必要はなく、コード内でDB接続を開くときに明示的に管理してSubscription_Idの値を設定する必要はありません。

データベースのSubscription_Id列にデフォルト値の制約を手動で設定する必要があります。現在のセッションのデフォルト値はSubscription_Idです。この値はレコードを挿入するときに設定され、暗黙的にデータベースレベルで後続のクエリとコマンドをフィルタリングするために使用されます。既存の列の場合は

ALTER TABLE SomeEntityTable ADD Subscription_Id nvarchar(128) 
    DEFAULT CAST(SESSION_CONTEXT(N'UserId') AS nvarchar(128)) 

:新しい列の場合

ALTER TABLE SomeEntityTable 
    ADD DEFAULT CAST(SESSION_CONTEXT(N'UserId') AS nvarchar(128) 
    FOR Subscription_Id 

列が前回異なるDEFAULT値を持っていた場合、また、その関連を削除するには良いでしょう廃止されたDEFAULT制約。既存の列のデフォルト値を更新する詳細については、hereを参照してください。

これらの列をモデルに含めないでください。エンティティクラスにそれらのプロパティを持つべきではありません。 Database Firstを使用している場合は、データベースからモデルを更新する際に、これらの列を除外/無視する必要があります。

EFコードを使用している場合の方法最初に、コードをAdd-Migrationで生成した後に、AlterColumn(またはCreateColumn)の手順をコードの移行に手動で含めることができます。すべてのエンティティテーブルのためにそれを実行します(。また、列を削除Down()メソッドを追加してもいいでしょう)

public override void Up() 
{ 
    AlterColumn("dbo.SomeEntityTable", "Subscription_Id", 
     c => c.String(
      nullable: false, 
      maxLength: 128, 
      defaultValueSql: "CAST(SESSION_CONTEXT(N'UserId') AS nvarchar(128))")); 
} 

警告:この移行を実行するときには、すでに既存のレコードを持っている場合は注意が必要空のSubscription_Idカラム値を持つテーブル(またはすでにレコードがあるテーブルに新しいSubscription_Idカラムを追加する場合)を使用します。空の列には、移行を実行している接続のSubscription_Idの値が入力されます。おそらく間違っています(既存のレコードをすべてその特定のサブスクリプションに関連付けることは望ましくありません)。その場合は、の値をUp()メソッドにSql()メソッドで明示的に含めることができます。このような何か:

Sql("UPDATE SomeEntitiesTable SET Subscription_Id= '19bc9b0d-28dd-4510-bd5e-d6b6d445f511' WHERE Id IN (1, 2, 5)"); 

コードファーストではまた、あなたのモデルクラスからSubscription_Idプロパティを削除する必要があります。できない場合は、少なくともSubscription_Id列の設定コードに明示的なIgnore()命令を追加すると、EFマッピングにそれらの命令を入れたくありません。

注:私はあなたがSESSION_CONTEXTUserIdパラメータを使用して、あなたのDBにおけるRLSポリシーを作成したことを、ここで仮定している、とDB接続を開くときに、アプリケーション・コードがDbConnectionInterceptorまたは類似した何かを経由して、その値を設定していること。

This page詳細情報が含まれています。

+0

"これらの列はモデルに含まれてはいけません。エンティティクラスにプロパティを持たないでください。データベースからモデルを更新する際に、これらの列を除外/無視するようにしてください。 "データベースの列を最初のEFから除外するにはどうすればよいですか?私はすでにサブスクリプションIDのデフォルト値を設定しています – Gunashekar

+0

私はDatabase Firstにはあまり慣れていません。この記事のコメント(https://stackoverflow.com/questions/38445897/how-to-exclude-certain-column-in-ef6-using-database-first)から、あなたは単にプロパティを削除することができます列がまだストアモデルにあるので、モデルを次回更新するときに再生成されないため、EFは列をクラスモデルに追加する新しい列としては考慮しません。 – Diana

関連する問題