How do I add a RowVersion attribute to a EF4 class - entity-framework

I am using EF4 and creating classes through the Entity design surface then generating the database from them. I want to add an attribute to some of the classes to show the timestamp they were last updated.
I have added a Version attribute to them, but I don't know which .Net datatype to associate with them so they become either Timestamp or RowVersion in the database when it is generated.
Any ideas?

You use byte[] type for rowversion/timestamp
Example use: http://www.ienablemuch.com/2011/07/using-checkbox-list-on-aspnet-mvc-with_16.html
If you are in the designer, just type in byte[] or System.Byte[], I think the field types dropdown selection on EF designer can be typed-in upon.
Given this DDL
create table Movie
(
MovieId int identity(1,1) not null primary key,
MovieName varchar(100) not null unique,
MovieDescription varchar(100) not null unique,
YearReleased int not null,
Version rowversion -- rowversion and timestamp are alias of each other
);
This is the class mapping:
public class Movie
{
    [Key]
    public virtual int MovieId { get; set; }
     
    [   Required, Display(Name="Title")
    ]   public virtual string MovieName { get; set; }
     
    [   Required, Display(Name="Description")
    ]   public virtual string MovieDescription { get; set; }
     
    [   Required, Display(Name="Year Released"), Range(1900,9999)
    ]   public virtual int? YearReleased { get; set; }
     
    [Timestamp]
// byte[] is the rowversion/timestamp .NET type
    public virtual byte[] Version { get; set; }
 
     
    public virtual IList<Genre> Genres { get; set; }             
}

As far as I know, rowversion is a relative binary value, not an actual time value. It increments for every insert and update that occurs. This allows you to compare values to determine which record is newer. Since it is relative, given a single rowversion value, you will know nothing, but given two rowversion values, you will know which is older and which is newer, but not by how much.
I don't know which .Net datatype to associate with them so they become either Timestamp or RowVersion in the database when it is generated.
I'm not sure, but most likely there isn't a datatype that will give you rowversion when going from model to database. You will have to change the database field type yourself, or add the field to the DB and bring the record up to your model. You could also generate the DDL and then modify it before creating the DB with it.
There is also another method where you can extend the functionality of the EF process by deriving from it's classes. You can then choose it yourself, but I'm not too familiar with how to do that.

Related

add-migration queries the database for the columns I'm trying to add, fails with "Error: Invalid column name 'newColumn1', 'newColumn2', 'newColumn3'"

I'm trying to add three columns to an existing table via code first migrations with EF Core (package version 3.1.8). When I run add-migration <name> -c <context> -o <output folder>, it's throwing this error (along with a massive stack trace...):
An error occurred while accessing the Microsoft.Extensions.Hosting services. Continuing without the
application service provider. Error: Invalid column name 'NewColumn1'.
Invalid column name 'NewColumn2'.
Invalid column name 'NewColumn3'.
Unable to create an object of type 'MyDbContext'. For the different patterns supported at
design time, see https://go.microsoft.com/fwlink/?linkid=851728
Really baffled by this. This is the fourth migration I've added today, none of the previous ones had this issue.
This migration should add the three columns, data for the predefined rows for these columns, and add a default value constraint to newColumn1. The column data types:
newColumn1: bit, defaults to 0
newColumn2: nvarchar(50)
newColumn3: nvarchar(50)
My entity before adding my trouble migration:
public class MyEntity
{
[Key]
public int Id { get; set; }
[MaxLength(50), Required]
public string AttributeName { get; set; }
[Required]
public bool Required { get; set; }
}
This entity changed to the following prior to attempting to add this migration:
public class MyEntity
{
[Key]
public int Id { get; set; }
[MaxLength(50), Required]
public string AttributeName { get; set; }
[Required]
public bool Required { get; set; }
public bool NewColumn1{ get; set; }
[MaxLength(50)]
public string NewColumn2 { get; set; }
[MaxLength(50)]
public string NewColumn3 { get; set; }
}
In MyDbContext.OnModelCreating, I have the following new code:
builder.Entity<MyEntity>().Property(x => x.NewColumn1).HasDefaultValue(false);
The IEntityTypeConfiguration<MyEntity> has also, as previously mentioned, been updated to have data for all new columns for the predefined rows. No rows exist in the database besides the predefined rows.
I have a theory as to what's going on. I think add-migration requires an instance of MyDbContext, and when it gets instantiated it verifies that the database looks the way it expects. The context expects the table represented by MyEntity to have the three new columns that are defined in the entity, but they don't exist in the database. What I'm curious of is why this just started now? This is my fourth migration of the day, my other migrations added tables, columns, data....why would this just now start becoming an issue?
The msft documentation link in the error makes me think I need to implement IDesignTimeDbContextFactory<MyDbContext>, configure it in such a way that it makes it not choke. But looking at the behavior of DbContextOptionsBuilder, it doesn't look like any of the provided options will allow me to bypass the behavior I'm getting.
The database has been updated with all previous migrations, and I checked the DbContextModelSnapshot file...the new columns aren't anywhere in there (as expected). The database I'm targeting is a local SQL Server database.

EF Core, DB First: How can I get the model classes I want?

I'm new to EF and trying database-first. Looks mostly ok but there are a few cases where model class fields aren't quite what I want.
Table columns ...
[Id] uniqueidentifier NOT NULL PRIMARY KEY,
[InsertedAt] datetime NOT NULL DEFAULT GETDATE(),
[UpdatedAt] datetime NOT NULL DEFAULT GETDATE()
Model fields ...
public Guid Id { get; set; }
public DateTime InsertedAt { get; set; }
public DateTime UpdatedAt { get; set; }
My model fields are all non-nullable so they will all get default values. Instead, I want Id to be nullable, and to get a constraint violation on an attempt to insert a null ID, because I want the client to have to create GUIDs. And I want timestamps to be autogenerated by the database for datetime columns on attemtpts to insert null.
I could hand-edit every model class to get what I want, but I'm wondering if there's a better way.
Thanks!

EntityFramework DatabaseGeneratedOption.Identity accepts and saves data instead of generating new one

Assuming this test model:
public class TestEntity
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid Id { get; set; }
public string Name { get; set; }
}
When I generate a new instance of it, Id is 00000000-0000-0000-0000-000000000000.
Saving such an instance in the database as a new row, results in a Guid being generated (which is different from the empty one).
However, if I provide a valid Guid in TestEntity.Id, the new row is created with the provided Guid instead of a newly computed one.
I would like this behavior to exists only when editing a row, not when creating it. This is to ensure a database-layer protection from attacks where a user normally shouldn't get to choose which data to input.
Off course this protection is present in other layers, but I want it in the database too. Is this possible? How can I tell EF to ignore model data when creating a new row?
DatabaseGeneratedOption.Computed descriptions says
the database generates a value when a row is inserted or updated
So clearely that's not an option. I don't want to change Id when updating a row. I only want to be sure no one can create a row and choose the Id.
I'd try to keep things simple. Make your set method protected, then you have two ways to generate Ids, You can generate it by yourself inside a constructor:
public class TestEntity
{
// no need to decorate with `DatabasGenerated`, since it won't be generated by database...
[Key]
public Guid Id { get; protected set; }
public string Name { get; set; }
public TestEntity()
{
this.Id = Guid.NewGuid();
}
}
...or you can let the database generate it for you. At least for SQL Server, it will be able to generate for int and Guid as well:
public class TestEntity
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid Id { get; protected set; }
public string Name { get; set; }
// no need to generate a Guid by yourself....
}
This will avoid people from setting a value to Id outside the class (therefore no one can choose a Guid for new rows, or modify from existing ones).
Of course, your team could use reflection to by-pass class definitions, but if that's the case, you need to have a talk with your team.
If you still want to make sure they won't cheat, then you'd have to do check before saving changes to database, maybe overriding SaveChanges() in your DbContext.
As a side note, for both int and Guid, values are not generated by Entity Framework. Decorating the property with [DatabaseGenerated(DatabaseGeneratedOption.Identity)] will tell Entity Framework to generate a column with a default value coming from the own database provider.

entity framework table with optional foreign keys

First of all, I'm new to Entity Framework and I'm trying to do a project using the Code-First model, so please forgive my ignorance on what may turn out to be a trivial problem...
I'm working on creating some POCO EF classes and I'm having difficulty figuring out how to setup some of the relationships in the DbContext derived class.
If I were to setup the tables with SQL, this is what they would look like (extraneous columns removed for clarity and brevity:
CREATE TABLE DBO.Application (
ApplicationId NUMERIC(18,0) IDENTITY(1,1) NOT NULL,
MinimumVersionId NUMERIC(18,0),
CurrentVersionId NUMERIC(18,0));
CREATE TABLE DBO.ApplicationVersion (
ApplicationVersionId NUMERIC(18,0) IDENTITY(1,1) NOT NULL,
ApplicationId NUMERIC(18,0) NOT NULL;
ALTER TABLE DBO.Application ADD
PRIMARY KEY (ApplicationId),
CONSTRAINT Application_FK1
FOREIGN KEY (MinimumVersionId)
REFERENCES DBO.ApplicationVersion (ApplicationVersionId),
CONSTRAINT Application_FK2
FOREIGN KEY (CurrentVersionId)
REFERENCES DBO.ApplicationVersion (ApplicationVersionId);
ALTER TABLE DBO.ApplicationVersion ADD
PRIMARY KEY (ApplicationVersionId),
CONSTRAINT ApplicationVersion_FK1
FOREIGN KEY (ApplicationId)
REFERENCES DBO.Application (ApplicationId);
The relevant part of the ApplicationModel POCO class is (Application DB Table shown above):
public class ApplicationModel
{
public long ApplicationId { get; set; }
public virtual ApplicationVersionModel CurrentVersion { get; set; }
public long? CurrentVersionId { get; set; }
public virtual ApplicationVersionModel MinimumVersion { get; set; }
public long? MinimumVersionId { get; set; }
public virtual IList<ApplicationVersionModel> Versions { get; set; }
}
And the ApplicationVersionM POCO class (ApplicationVersion DB Table shown above):
public class ApplicationVersionModel
{
public virtual ApplicationModel Application { get; set; }
public long ApplicationId { get; set; }
public long ApplicationVersionId { get; set; }
}
So far, in the OnModelCreating method of the class that inherits from DbContext, I have this:
modelBuilder.Entity<ApplicationModel>()
.HasMany<ApplicationVersionModel>(a => a.Versions)
.WithRequired(av => av.Application)
.HasForeignKey(a => a.ApplicationId);
This is to establish the one to many relationship between Application and ApplicationVersion.
Where I'm getting confused is how to write the entries for the CurrentVersion and MinimumVersion fields. Each of these are to hold a value that would be found in ApplicationVersion.ApplicationVersionId (the primary key). However, these fields are nullable in the database and, therefore, optional.
I'm getting lost in all the options like:
WithMany - I know this one isn't it as I'm pointing to a single record
WithOptionalDependant
WithOptionalPrincipal
WithRequired - I don't think this is it since the field is nullable
And then, I'm not exactly sure what methods would be chained after that.
Any help would be appreciated. It would also be beneficial if, in your answers, you could explain WHY I need to do it that way. Knowing why will help me (and possibly others that may read the question) understand the processes and relationships better.

EF Code First giving me error Cannot insert explicit value for identity column in table 'People' when IDENTITY_INSERT is set to OFF. [duplicate]

This question already has answers here:
EF code first: Cannot insert explicit value for identity column in table '' when IDENTITY_INSERT is set to OFF
(3 answers)
Closed 4 years ago.
I'm trying out Entity Framework 4's Code First (EF CodeFirst 0.8) and am running into a problem with a simple model that has a 1 <--> 0..1 relationship, between Person and Profile. Here's how they're defined:
public class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime? DOB { get; set; }
public virtual Profile Profile { get; set; }
}
public class Profile
{
public int ProfileId { get; set; }
public int PersonId { get; set; }
public string DisplayName { get; set; }
public virtual Person Person { get; set; }
}
The DB context looks like this:
public class BodyDB : DbContext
{
public DbSet<Person> People { get; set; }
}
I didn't define a DbSet for Profile because I consider People to be its aggregate root. When I try to add a new Person - even one without a Profile with this code:
public Person Add(Person newPerson)
{
Person person = _bodyBookEntities.People.Add(newPerson);
_bodyBookEntities.SaveChanges();
return person;
}
I get the following error:
Cannot insert explicit value for identity column in table 'People' when IDENTITY_INSERT is set to OFF.
The newPerson object has a 0 for the PersonId property when I call People.Add(). The database tables are People and Profiles. PersonId is the PK of People and is an auto-increment Identity. ProfileId is the PK of Profiles and is an auto-incement Identity. PersonId is a non-null int column of Profiles.
What am I doing wrong? I think I'm adhering to all the EF Code First's convention over configuration rules.
I get the following error:
Cannot insert explicit value for identity column in table 'People' when IDENTITY_INSERT is set to OFF.
I think that the IDENTITY_INSERT is the Auto Increment functionality which is off.
So, check the field PersonId in the database to see if it is an identity.
Besides, maybe this will fix your problem too.
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int PersonId { get; set; }
This will occur if you perform the following steps:
Create a non-identity PK field on a table.
Infer the Entity Model from that table.
Go back and set the PK identity to true.
The Entity Model and the database are out of sync. Refreshing the model will fix it. I had to do this just yesterday.
If you are using EF Code First, then, in addition to adding the [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] annotation attribute to the model.cs file as others have suggested here, you also need to make the same effective change on the modelMap.cs files (the fluent mapping instructions):
Change from:
this.Property(t => t.id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
to:
this.Property(t => t.id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
(I used the EF Power Tools to generate the entity models and the default mapping files, then later turned one Id column into a prmary key column and set it to IDENTITY in Sql Server, therefore, I had to update the attribute and the default mapping file.)
If you don't change it in both places, you'll still get the same error.
You situation reminds me situation I experience with EF Code First when PrimaryKey and ForeignKey are the same column.
There is no direct way to refresh the model, however the same effect can be achieved in 2 steps.
Comment out ProfileId in Profile class. Recompile and update database.
Uncomment Profile Id, add DatabaseGeneratedAttribute and update database again.
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.None), Key]
This way the generated ProfileId column becomes Key without Identity.
If you are using EF core and the fluent interface like me, I've found that the Scaffold-DbContext utility I've used to create the model from an existing db, generate a line for my column like that:
entity.Property(e => e.id).ValueGeneratedNever();
After I've changed the DB adding the IDENTITY attribute to my id, I had to change the row in:
entity.Property(e => e.id).ValueGeneratedOnAdd();
other than adding the [DatabaseGeneratedAttribute(DatabaseGeneratedOption.None), Key] decorator to the id field in my model class.
I'm not even sure if the latter is necessary. After resolved with the former fix, I didn't try to remove it.
I didn't have this problem until I added a composite key , so once I had 2 primary keys this occurred with EF 6.x.x
On my Key "Id" which has Identity Specification set to true I needed to add
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
Model properties now:
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
[Key, Column("Id", Order = 1)]
public int Id { get; set; }
[Key, Column("RanGuid", Order = 2)]
public string RanGuid { get; set; }
For the benefit of searchers: I got this error, but the above fixes did not work. It was due to an error on my part.
On my tables, I have a Guid Primary Key (non-clustered) and an int index.
The error was happening when trying to update the 'Post' with the 'Blog' info as a navigation property. See classes below:
public class Blog
{
public Guid BlogId { get; set; }
public int BlogIndex { get; set; }
// other stuff
}
public class Post
{
public Guid PostId { get; set; }
public int PostIndex { get; set; }
// other stuff
public Blog Blog { get; set; }
}
The issue was that when I was converting DTO's to models, the BlogId was being changed to a new Guid() (I made an error in the mapping). The resulting error was the same as detailed in this question.
To fix it, I needed to check the data was right when being inserted (it wasn't) and fix the incorrect change of data (in my case, the broken mapping).
Got this error in EF6, looked at the database and everything looked right with Identity Specification set to Yes. I then removed the different migrations and made one new migration from current models and then everything started working. Fastest solution since the application was not live yet and still in development.
Cannot insert explicit value for identity column in table
'Test' when IDENTITY_INSERT is set to OFF.
Here is the solution. Also see the attachment for more help.
Navigate to your EF model ".edmx" file >> Open it >> Now right click on the diagram and choose 'Update Model from Database'.
This will fix it because you made PK the Identity in your DB after you created your EF model.
help to recreate steps stated above
In my case it seems that EF doesn't like other type than INT identity field - mine was a BYTE (TINYINT on the SQL side).
Since I was able to update my project and change it to INT on the SQL, after re-running the Reverse Engineering Code First on VisualStudio, the error has immediately ceased to occur.
In my case it seems that EF doesn't like other type than INT identity field - mine was a BYTE (TINYINT on the SQL side).
I had this error too using PK of tinyint type. It's not that EF doesn't like it, it's seems that, unlike other cases, you have to specify that in your configuration like this:
this.Property(t => t.TableID).HasColumnName("TableID").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);