Entity Framework 6.1 (code-first) has added the possibility of adding indexes via the IndexAttribute
. The attribute takes a parameter for specifying whether the index should be clustered or non-clustered.
At the same time, AFAIK, Entity Framework requires every entity to have a primary key (annotated with the KeyAttribute
), and that primary key is always created as a clustered key.
Therefore, as soon as I apply the IndexAttribute
with IsClustered = true
, I get an error because, due to the key, there already is a clustered index.
So, how can I create a clustered index that is not the primary key using the IndexAttribute
? Is the IsClustered
property of the IndexAttribute
usable at all?
(For a little more context: I'm mapping a table that is only used for reading via LINQ queries. I do not need to actually insert, update, or delete entities from that table. Therefore, I don't need a primary key at all. Ideally, I'd like a table without a primary key, but with a non-unique, clustered index optimized for reading.)
Edit (2014-04-11): See also https://entityframework.codeplex.com/workitem/2212.
Telling you the truth - the IndexAttribute is totally redundant and not suitable for professinal development. They lack core functionality and focus on stuff that makes little sense.
Why? Because it never can will and should be as flexible as a build script. Clustered index is only one thing - the next thing I would miss is a filtered index, mostly in teh form of "Unique index for non null, non-unique index for null" on a field, which I happen to use very regularly for optional unique codes (because in SQL Server a NULL is equal to another NULL in SQL generation, so you can only have one NULL at a time in a unique index).
If I were you I would stay away from database generation - and migrations - and use a classical setup/migration scripts approach. Thta is something where you can do more complex multi step migrations without possibly ata loss. EF does not handle anything but the most basic scenarios - and in these areas I doubt that is enough. Can be it is because I also and mostly work on large databases where we do our changes very carefully - adding an index can take some time when you hit a double digit number of billions of rows (!0+).
I would prefer the developers would focus on some ofher missing areas tht can not easily and better be worked around, like performance, like core ORM features (better enums, second level caching, bulk delete API, more performance inserts and updates - all things that are doable). Code First is nice. Code First generating and maintainign the database is - painfull outside extremely simple scenarios.
I write here my solution if anyone still interested in this subject. Below code changes output of add-migration command.
You can register this generator in migration configuration:
And here is the generated migration code:
Here is the article about custom MigrationCodeGenerator.
Below is the code based on raditch's answer that worked for me. This allows the primary keys to default to clustered. It may need tweaked as we do not use the built in ef migrations to actually handle the changes
There can only be one clustered index on a table and by default Entity Framework/Sql Server puts it on the primary key.
So what use is the
IsClustered
attribute on an index that is not the primary key? Good question! (+1)This class:
will generate this migration:
Alter the migration to this:
And that should create your table without a primary key but with the clustered index on the other columns
EDIT In your scenario where you don't need to insert, update or delete data, you don't need a full blown entity, you could use raw sql queries to populate the classes. You would need to add your own sql to the migration to create the table because EF won't automate it, but that means you can create the table and index just as you want it.
You can derive your own class from SqlServerMigrationSqlGenerator and change pk creation there:
full example here https://entityframework.codeplex.com/workitem/2163