Entity Framework 6.1 (code-first) ha aggiunto la possibilità di aggiungere indici tramite l' IndexAttribute
. L'attributo accetta un parametro per specificare se l'indice deve essere cluster o non cluster.
Allo stesso tempo, AFAIK, Entity Framework richiede ogni entità di avere una chiave primaria (annotato con la KeyAttribute
), e la chiave primaria viene sempre creato come chiave cluster.
Pertanto, non appena applico IndexAttribute
con IsClustered = true
, ottengo un errore perché, a causa della chiave, v'è già un indice cluster.
Quindi, come posso creare un indice cluster che non sia la chiave primaria utilizzando l' IndexAttribute
? La proprietà IsClustered
di IndexAttribute
utilizzabile?
(Per un po 'più di contesto: sto mappando una tabella che viene utilizzata solo per la lettura tramite query LINQ. Non è necessario inserire, aggiornare o eliminare effettivamente entità da quella tabella. Pertanto, non ho bisogno di una chiave primaria Idealmente, mi piacerebbe una tabella senza una chiave primaria, ma con un indice cluster non univoco ottimizzato per la lettura.)
Modifica (2014-04-11): vedere anche https://entityframework.codeplex.com/workitem/2212 .
Può esistere un solo indice cluster su una tabella e, per impostazione predefinita, Entity Framework / Sql Server lo inserisce sulla chiave primaria.
Quindi, a che serve l'attributo IsClustered
su un indice che non è la chiave primaria? Buona domanda! (+1)
Questa classe:
public class Blog
{
[Key()]
public int Id { get; set; }
[MaxLength(256)]//Need to limit size of column for clustered indexes
public string Title { get; set; }
[Index("IdAndRating", IsClustered = true)]
public int Rating { get; set; }
}
genererà questa migrazione:
public override void Up()
{
CreateTable(
"dbo.Blogs",
c => new
{
Id = c.Int(nullable: false, identity: true),
Title = c.String(maxLength: 256),
Rating = c.Int(nullable: false),
});
.PrimaryKey(t => t.Id)
.Index(t => t.Rating, clustered: true, name: "IdAndRating");
}
Alter la migrazione a questo:
public override void Up()
{
CreateTable(
"dbo.Blogs",
c => new
{
Id = c.Int(nullable: false, identity: true),
Title = c.String(maxLength: 256),
Rating = c.Int(nullable: false),
});
CreateIndex("dbo.Blogs",
new[] { "Rating", "Title" },
clustered: true,
name: "IdAndRating");
}
E questo dovrebbe creare la tua tabella senza una chiave primaria ma con l'indice cluster sulle altre colonne
MODIFICA Nello scenario in cui non è necessario inserire, aggiornare o eliminare dati, non è necessaria un'entità completa, è possibile utilizzare query sql raw per popolare le classi. Dovresti aggiungere il tuo sql alla migrazione per creare la tabella perché EF non lo automatizzerà, ma ciò significa che puoi creare la tabella e l'indice come vuoi tu.
È possibile derivare la propria classe da SqlServerMigrationSqlGenerator e modificare la creazione di pk qui:
public class NonClusteredPrimaryKeySqlMigrationSqlGenerator : SqlServerMigrationSqlGenerator
{
protected override void Generate(System.Data.Entity.Migrations.Model.AddPrimaryKeyOperation addPrimaryKeyOperation)
{
addPrimaryKeyOperation.IsClustered = false;
base.Generate(addPrimaryKeyOperation);
}
protected override void Generate(System.Data.Entity.Migrations.Model.CreateTableOperation createTableOperation)
{
createTableOperation.PrimaryKey.IsClustered = false;
base.Generate(createTableOperation);
}
protected override void Generate(System.Data.Entity.Migrations.Model.MoveTableOperation moveTableOperation)
{
moveTableOperation.CreateTableOperation.PrimaryKey.IsClustered = false;
base.Generate(moveTableOperation);
}
esempio completo qui https://entityframework.codeplex.com/workitem/2163