a.k.a Code Firstで複数のID列を作成するにはどうすればよいですか?
クラスタリングのパフォーマンスのため、一般的な推奨事項は、newid()
で作成されたGUID)の代わりに自動インクリメント整数列を使用することです。
列を自動インクリメントとして宣言するには、注釈[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
で列を指定する必要があります。
ただし、テーブルに含めることができるIDは1つだけです。
そのため、次のような基本モデルから始めます。
public abstract class ModelBase {
// the primary key
public virtual Guid Id { get; set; }
// a unique autoincrementing key
public virtual int ClusterId { get; set; }
}
次のように設定する方法は次のとおりです。
ClusterId
は自動インクリメントされます[〜#〜] fyi [〜#〜]、コードで自動的に生成したい場合は、Idフィールドの注釈をスキップして次のようなことを行うことができます。
public abstract class AbstractContext : DbContext {
/// <summary>
/// Custom processing when saving entities in changetracker
/// </summary>
/// <returns></returns>
public override int SaveChanges()
{
// recommended to explicitly set New Guid for appropriate entities -- http://msdn.Microsoft.com/en-us/library/dd283139.aspx
foreach (var entry in ChangeTracker.Entries<ModelBase>().Where(e => e.State == EntityState.Added) ) {
// only generate if property isn't identity...
Type t = entry.Entity.GetType();
var info = t.GetProperty("Id").GetCustomAttributes(
typeof(DatabaseGeneratedAttribute), true).Cast<DatabaseGeneratedAttribute>().Single();
if (info.DatabaseGeneratedOption != DatabaseGeneratedOption.Identity) {
entry.Entity.Id = Guid.NewGuid(); // now we make it
}
}
return base.SaveChanges();
}
}
これは、Entity Framework 5で機能しました。
ClusterId
をIDとして宣言します(注釈)
_[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public override int ClusterId { get; set; }
_
移行する
PkプロパティId
をIdentityとして宣言します、もう1つが更新された後
_[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public override Guid Id { get; set; }
_
Id
が主キーであると想定しているため、_[Key, Required]
_は不要です_add-migration TrickEfIntoAutogeneratingMultipleColumns
_のような移行コードを作成します
Up()
メソッドのAlterColumn
ステートメントで、defaultSqlValue
[.____を宣言して、GUID=を自動生成するようにデータベースに指示します。 ]AlterColumn(theTable, "Id", c => c.Guid(nullable: false, identity: true, defaultValueSql: "newid()"));
これは、両方の列がIDであると想定し、それに応じて反応するという意味で、EFを「だましている」ようです。移行中、別の列をIDにしようとしますが、それがサイレントに失敗した場合は気にしないようです。つまり、1つはIDとしてマークされ、もう1つはデフォルト値にマークされます。
通常のコード操作中、EFはSaveChanges/ChangeTrackingのステップを通過しますが、Id
プロパティをIdentityとして認識するため、EFは完全に 「一時キーの割り当て」 であるため、デフォルトの0000000 ...値を使用しようとせず、代わりに指定したデフォルト値関数を使用してデータベースに生成させます。
(このフィールドにComputed
として注釈を付けると同じことを成し遂げると思っていましたが、...質問で言及したエラー... boo ...)
また、ClusterId
フィールドもコード内のIDであり、実際にはデータベース内のIDであるため、同様に自動インクリメントされます。