50

I am using code first approach in a ASP.NET MVC 3 application and all integer primary keys in models (public int Id { get; set; }) are by default configured as an identity with auto-incrementing. How to disable this and enable a way to manually enter the integer for the primary key?

The actual situation is that the Id integers have a special meaning and I would therefore like to have them choosable at creation and later editable. It would be ideal if in case the integer is not given at creation time it is auto-incremented, else the specified value is used. But editable primary fields is my primary need. Is there any way to do this elegantly in ASP.NET MVC 3?

frennky
  • 12,581
  • 10
  • 47
  • 63
gw0
  • 1,533
  • 2
  • 12
  • 13

8 Answers8

65

Use these data annotation options:

  • [System.ComponentModel.DataAnnotations.KeyAttribute()]
  • [System.ComponentModel.DataAnnotations.DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.None)]
Greg
  • 666
  • 6
  • 3
  • 4
    **NAMESPACE CHANGE:** It is 2015 and the namespacing has changed for this answer: `[System.ComponentModel.DataAnnotations.KeyAttribute()] [System.ComponentModel.DataAnnotations.**Schema**.DatabaseGenerated( System.ComponentModel.DataAnnotations.**Schema**.DatabaseGeneratedOption.None)]` – Cos Callis May 13 '15 at 17:39
  • 6
    Also, the "Attribute" part of "KeyAttribute" isn't needed and there little reason not to put a "Using" at the top: `using System.ComponentModel.DataAnnotations;using System.ComponentModel.DataAnnotations.Schema;[Key][DatabaseGenerated(DatabaseGeneratedOption.None)]` – WernerCD Oct 14 '15 at 00:01
31

You can use FluentMapping:

modelBuilder.Entity<*entityname*>().Property(m => m.*fieldname*)
             .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
William Haack
  • 429
  • 4
  • 4
16

If you want to use fluent api with EntityFramework Core 2.0 you write:

modelBuilder.Entity<*myEntity*>()
  .Property(e => e.*myFieldname*)
  .ValueGeneratedNever();
René
  • 3,413
  • 2
  • 20
  • 34
10

use attribute :

public class MessageSubject
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int Id { get; set; }
        public string Title { get; set; }
        public string Comment { get; set; }
        public bool BuildIn { get; set; }
    }
pixparker
  • 2,903
  • 26
  • 23
2

I have just installed the latest accepted EntityFramework.dll version 5.0.0, I believe ...

however, I get confused half the time as there is a Runtime Version of v4.0.30319 and a Version of 4.4.0.0 but, I am sure from the website I got referred to in my searching (which told me to install via "Package Mangager Console" from which you get to via menu within VS "Tools|Library Package Manager|Package Manager Console" and typing at the "PM>" prompt "Install-Package EntityFramework [optional: version number or -Pre for the lastest pre-release (beta version)]") it was 5.0.0.

... , and there is an attribute "System.CompnentModel.DataAnnotations.DatabaseGenerated(Computed, Identity or None) (previous version) or [...].Schema.DatabaseGenerated (latest version)" which you could use. So either use this attribute or use fluent mapping idea as mentioned above (by William Haack (edited by Remo Gloor)) and if not code first (i.e. changing production) then as also mentioned above (by Adam Tuliper) you will need to write and execute a one off script to turn off identity insert. On top of that if you do not supply an ID you can simulate an identity insert by retriving the MAX(ID) + 1 on your table in code (and keep in mind concurrency issues on a multi-user environment) or in a trigger. Alternatively if you wanted to plug holes, as the expression goes, you could probably do this in a trigger as well by intercepting the inserted row and checking if the ID column is set, if so proceed with the insert otherwise, set the value first. One approach to plug holes is to use that trick (which I saw on some web-site that I cannot remember, so I am guessing a little here) where you effectively do an anti-inner join from some large-table with a just a single column of rownumbers to your table to find the first available non used identity number (i.e. find the first rownumber that is not a member of the target table).

In SQL Server 2005 and beyond:

CREATE TRIGGER updInsYourTable_PlugHolesOnIDIfNull 
ON YourTable
FOR update, insert AS
BEGIN
    DECLARE @ID INT
    SELECT @ID = ID FROM INSERTED
    IF @ID IS NULL
    BEGIN
        ;WITH CTE_StagedNumbers AS
        (
            SELECT ROW_NUMBER() OVER (ORDER BY o.object_id) AS NextFreeIdentity
            FROM (  SELECT object_id FROM sys.objects
                 -- UNION ALL 
                 -- SELECT object_id FROM sys.objects
                 /* NB: Here if sys.objects is not larger enough say on a small schema 
                    configured database then use a different table otherwise you can 
                    always union all on the same table as many times as you want to 
                    double, triple etc. its size. */
                 )  o
        )
        UPDATE YourTable
        SET ID = (
                    SELECT TOP 1 NextFreeIdentity
                    FROM CTE_StagedNumbers
                    WHERE NextFreeIdentity NOT IN (SELECT ID FROM YourTable)
                 )
        WHERE ID IS NULL
    END
END
GO

Note, the the CTE_StagedNumbers is not necessary it is just there for emphasis and the main trick is not necessarily in the setting up of the row number but, if you were to set up a permanent staging table (say StagedNumbers) with just a single integer column with no auto-identity (say NextFreeIdentity INT NOT NULL PRIMARY KEY), (Aside NB: YourTable definition for your ID column must accept null's as we are using an after trigger) pre-filled with consequtive positive-integer values starting at 1 using the above technique, then remove the CTE altogether and replace the CTE_StagedNumbers in the final select with StagedNumbers then this will be most efficient.

Glen
  • 802
  • 1
  • 11
  • 27
  • Yes, a trigger could be one approach, but directly accessing and manipulating with SQL databases is not in the spirit of MVC frameworks. – gw0 Dec 10 '12 at 13:27
1

If this is an identity field in the database you cant. Well you can by setting identity insert off on the database side but by good practice you shouldn't unless bulk inserting records. If you don't want this as an identity set the identity option to false in the DB for that column.

Adam Tuliper
  • 29,982
  • 4
  • 53
  • 71
  • I am using the code first approach, that means that the database gets generated from the code. I only mentioned what can be seen in the database, because I think it is the root of the problem. So is there a data annotation for disabling automatic identity fields options? – gw0 Aug 28 '11 at 13:07
  • 2
    So what is the most non-hackish way to pass "SET IDENTITY_INSERT YourTableName OFF" (or sth) to the database at their creation time using code first approach? – gw0 Aug 28 '11 at 13:11
  • ah.. code first. Are you using [Key()]? If so I think you are somewhat stuck. I believe its meant for more simple scenarios. In your case you don't want the auto number generated but you still want an index Im assuming. The Key() field unfortunately doesn't give you this control so I would remove the Key field. If you are naming Id everywhere and not using a key() attribute I would seriously consider changing it as a DB field named Id does no one any good and when you link across tables (fk relations) its weird to say Customer.Id = OtherTable.CustomerId so I would keep it consistent. – Adam Tuliper Aug 29 '11 at 03:03
  • btw note some comments here: http://stackoverflow.com/questions/5813190/how-to-stop-ef4-1-code-first-to-create-culstered-index-for-the-entity-pk – Adam Tuliper Aug 29 '11 at 03:04
  • I figured out that turning identity off on the database is not as trivial as an alter table.... But a working simple solution is here: http://stackoverflow.com/questions/7227812/convert-and-modify-a-model-field-as-an-datacolumn-object – gw0 Aug 29 '11 at 10:02
  • nice! I hadn't seen this attribute before. here's another one: http://stackoverflow.com/questions/6642274/entity-framework-4-1-databasegeneratedoption-identity-performance – Adam Tuliper Aug 29 '11 at 15:22
0

Removing the Required attribute from a foreign key table did it for me.

DevDave
  • 6,700
  • 12
  • 65
  • 99
0

By Using Code First Approach

1)My Properties.class

 `  [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int CId { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int CNo { get; set; }`

2)In contextdb.class

`protected override void OnModelCreating(ModelBuilder modelBuilder)

{ modelBuilder.Entity() .HasKey(o => new {o.CId,o.CNo});}`

syed haris
  • 29
  • 1