I've added Entity Framework to an existing project with existing tables. These tables contains a couple of uniqueidentifier columns that is NULL. When I load data from these my model-property is also null and not Guid.Empty. I've tried setting the default value using both the constructor and
AlterColumn("tblItems", "ThreadRoot", c => c.Guid(nullable: true, defaultValue: Guid.Empty));
but it still return null.
How can I achieve this?
When I load data from these my model-property is also null and not Guid.Empty
That's because the data already present will contain null, because they were stored before you issued the AlterColumn method. The default value will be written when a new record is inserted, when the appropriate column is not set.
In your model, just add the default value to the property:
public class Item {
public Guid ThreadRoot { get; set; }
public Item() {
ThreadRoot = Guid.Empty; //default value
}
}
Related
I was trying to seed data in a migration using the SeedData method, and one of the fields of this model was an Enum that can have several values. The issue is that when I generate the migration, that specific field is never populated in the migration. It always relays on default value even when I'm trying to set it to something different. I also tried editing one of the already seeded objects included in a previous migration and it's also not generating an UpdateData migration. I manually tested adding myself the UpdateData statement but I wanted to know if we're doing something wrong with SeedData and Enum values.
SourceType.cs
public enum SourceType {
Email,
Sms,
Phone
}
Source.cs
public class Source {
[Key]
public int Id {get; set;}
public string Name {get; set;}
public SourceType Type {get;set;}
}
HasData use
...
modelBuilder.Entity<Source>().HasData(
new Source{
Id = 1,
Name = "Email Source",
Type = SourceType.Email
})
...
BunchOfDateNumbers_Migration.cs Up method
migrationBuilder.InsertData(
table: "Source",
columns: new[]{"Id", "Name"},
values: new[] {1, "Email Source"})
Am I doing something wrong? Do we have to specify enum values manually?
EDIT:
We also set this value by default:
modelBuilder.Entity<Source>(
entity =>
{
entity.Property(e => e.SourceType).HasDefaultValueSql("1");
});
EF Core uses the CLR default to determine if the SQL DEFAULT should be used. Since SourceType.Email is the CLR default (0) it doesn't send an INSERT value so the DEFAULT constraint can be used. There are several ways to "fix" this.
First, you could just start your enum at 1:
enum SourceType {
Email = 1,
Sms,
Phone
}
Or second, you could add a better enum value for the default.
enum SourceType {
Unknown, // "None" or "Default" are also good names
Email,
Sms,
Phone
}
Or third, you can make the property nullable so that null becomes the default CLR value instead of 0.
class Source {
// Nullable to allow both using the DEFAULT and inserting SourceType.Email
public SourceType? Type {get;set;}
}
I have a class named Address that is a system versioned table. I am trying to insert into this table using entity framework context adding an object to the context and then doing a SaveChanges call. This worked as expected when the table was not system versioned. In my model that looks something like this minus some properties that are not related to this question:
[DataMember]
public System.DateTime SysStartTime
{
get { return _sysStartTime; }
set
{
if (_sysStartTime != value)
{
_sysStartTime = value;
OnPropertyChanged("SysStartTime");
}
}
}
private System.DateTime _sysStartTime;
[DataMember]
public System.DateTime SysEndTime
{
get { return _sysEndTime; }
set
{
if (_sysEndTime != value)
{
_sysEndTime = value;
OnPropertyChanged("SysEndTime");
}
}
}
private System.DateTime _sysEndTime;
[DataMember]
public int AddressId
{
get { return _addressId; }
set
{
if (_addressId != value)
{
if (ChangeTracker.ChangeTrackingEnabled && ChangeTracker.State != ObjectState.Added)
{
throw new InvalidOperationException("The property 'AddressId' is part of the object's key and cannot be changed. Changes to key properties can only be made when the object is not being tracked or is in the Added state.");
}
_addressId = value;
OnPropertyChanged("AddressId");
}
}
}
private int _addressId;
This historical table was created as per documentation with a generated always property hidden and default value.
When I try to do a simple insert I get the Error:
Cannot insert value into generated always identity column
I understand what the error is saying but I don't know how to fix it. I have tried to remove the SysStartTime and SysEndTime properties from the model but that gives me validation issues. I have also tried not setting the properties on the model as DataMember and even IgnoreDataMember but the result was always the same. My question is how can I remove the SysStartTime and SysEndTime properties from the object with the address model before adding it to the context? Thank you.
UPDATE:
I have used this code to create my temporal table:
ALTER TABLE [dbo].[Address] ADD
[SysStartTime] datetime2(0) GENERATED ALWAYS AS ROW START HIDDEN NOT NULL CONSTRAINT DF_Telco_SysStartTime DEFAULT '1900-01-01 00:00:00',
[SysEndTime] datetime2(0) GENERATED ALWAYS AS ROW END HIDDEN NOT NULL CONSTRAINT DF_Telco_SysEndTime DEFAULT '9999-12-31 23:59:59',
PERIOD FOR SYSTEM_TIME ([SysStartTime], [SysEndTime])
ALTER TABLE [dbo].[Address]
SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = [dbo].[Address_History]));
I have found a workaround for this issue by modifying the model.edmx file and adding to the SysStartTime and SysEndTime StoreGeneratedPattern="Computed" property.
For the first time ever I'm using GUIDs for PK values in my POCO classes which has presented a rather irritating problem being that I can't seem to get data added to my tables.
Here's an example addition:
public partial class EntityType
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
public string Type { get; set; }
public bool Deleted { get; set; }
}
Here's my migration configuration seed method:
internal sealed class Configuration : DbMigrationsConfiguration<AC.WebGUI.Models.OrtundDataModel>
{
protected override void Seed(AC.WebGUI.Models.OrtundDataModel context)
{
// Prepopulate Entity Types.
if (!context.EntityTypes.Any())
{
context.EntityTypes.AddOrUpdate(
new EntityType { Id = Guid.NewGuid(), Type = "Supplier" },
new EntityType { Id = Guid.NewGuid(), Type = "Distributor" },
new EntityType { Id = Guid.NewGuid(), Type = "Staff" },
new EntityType { Id = Guid.NewGuid(), Type = "Customer" },
new EntityType { Id = Guid.NewGuid(), Type = "Pharmacy" }
);
context.SaveChanges();
}
}
Note that in both classes, I'm specifying a Guid.NewGuid() value for my Id property.
This, however, has not got me around the error:
System.Data.SqlClient.SqlException: Cannot insert the value NULL into column 'Id', table 'Ortund.dbo.EntityTypes'; column does not allow nulls. INSERT fails.
Obviously calling Guid.NewGuid() can't be a null value so I'm very unsure of how to proceed at this point. I figured that if I added it to the constructor on the class that defines the table, I could remove it from the actual implementation of that class, however, whether I take it out of the constructor or out of the implementation, the error persists.
How can I get these Guids added to my table data without any errors? What am I missing?
Edit - Addressing duplicate question
Since my question has been marked as a duplicate of this question which deals with using the specified data annotation to make EF automatically generate the GUID value for the PK column on the table, I thought I'd just explain how mine is different.
The idea is the same, true enough, but the implementation has diverged from what is discussed in the other question so I've arrived at a totally different solution for my own project which involved removal of this data annotation whereas the solutions proposed in the other question keep it and make other changes to the data model.
Figured I'd answer this before it gets closed.
Per comments, simply removing the DatabaseGenerated(DatabaseGeneratedOption.Identity)] annotation from the PK property fixed the problem though I did keep the assignment in the constructor.
SQL server 2005 database table has a column 'createdon' for which default value set to getdate(). I am trying to add a record using entity framework. 'createdon' column is not getting updated.
Did I miss any property in Entity framework, please suggest.
This is one of the few issues that are problematic with Entity Framework. Say you have a class that looks like this:
public class MyEntity
{
// Id is a PK on the table with Auto-Increment
public int Id { get; set; }
// CreatedOn is a datetime, with a default value
public DateTime CreatedOn { get; set; }
}
Now, you want to insert a new element:
using(var context = new YourContext())
{
context.MyEntities.Add(new MyEntity())
}
Entity Framework knows how to handle an auto-increment primary key because of the definition in the EDMX. It will not try to insert a value for the Id property. However, as far as Entity Framework is concerned, CreatedOn has a value: the default DateTime. Because Entity Framework cannot say "well, it has a value but I should ignore it", it will actively insert the record with the CreatedOn property value, bypassing the default value on your column definition on your table.
There is no easy way to do this. You can either actively set the CreatedOn property to DateTime.Now when you insert that item. Or you can create an interface and an extension method pair:
public interface ICreatedOn
{
public DateTime CreatedOn { get; set; }
}
public partial class MyEntity : ICreatedOn
{
}
public static TEntity AsNew<TEntity>(this TEntity entity) where TEntity : ICreatedOn
{
if(entity != null)
entity.CreatedOn = DateTime.Now;
return entity;
}
using(var context = new YourContext())
{
context.MyEntities.Add(new MyEntity().AsNew())
}
Edit: To expand on this point, the reason why this is an unresolvable issue is because of the meaning behind an autoincrement field and a field with a default value constraint. An auto-increment field should, by definition, always be handle by the server, using a seed and all that jazz. You cannot specify a value for an auto-increment field on an insert unless you have used SET IDENTITY INSERT ON. A default value, however, is just a hint that say "if I don't specify any value, use this". Because value types in .NET cannot be null, there will always be a value and Entity Framework cannot infer that the default value for that field, at that time, means that you want it to be defaulted on the SQL server.
Next to using the designer and some more nifty stuff shown already, you can also mark the columns as being calculated by simply setting the DatabaseGenerated attribute on the field:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime CreatedOn { get; set; }
You can set StoreGeneratedPattern to Computed (as Malcolm suggested) in the GUI of the entity data model as well.
Open your .edmx file in Visual Studio
Open the properties of the field (click on the field -> hit
F4 or right click->properties)
Set StoreGeneratedPattern to Computed in the properties window
as shown below:
I've got around this issue by telling EF that the column is 'computed', and should therefore be left alone for inserts.
If you look in the configuration for the generated entity
namespace Data.Context
{
// Table
internal partial class MyTableConfiguration : EntityTypeConfiguration<MyTable>
{
public MyTableConfiguration(string schema = "dbo")
{
ToTable(schema + ".MyTable");
HasKey(x => x.Id);
Property(x => x.ColumnName).HasColumnName("ColumnName").IsOptional().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
....
I'm getting this error on EF.
Cannot insert explicit value for identity column in table
'GroupMembers_New' when IDENTITY_INSERT is set to OFF.
The column on the Db is identity increment and on the EF design file, StoreGeneratedPattern is identity as well. Seems like EF is trying to insert 0 every time I try to save.
Some suggestions says ID is reserved on tables or drop the table and rerun the scripts.
Any ideas?
Here's some code:
GroupMember groupMember = new GroupMember();
groupMember.GroupId = group.Id;
groupMember.UserId = (new UserId(group.Owner));
//groupMember.Id = _groupContext.GroupMembers.Count();
group.GroupMembers.Add(groupMember);
_groupContext.SaveChanges();
I have run into this before. This error means you are trying to assign a value explicitly to a column where the database automatically assigns it.
Suggestion:
Update your edmx file to reflect any changes you may have made in the database.
If the database automatically assigns the value, you should see the "IsDbGenerated=true" attribute in your designer file under that property. If it's not there, you can add it manually.
Try this:
using System.ComponentModel.DataAnnotations.Schema;
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public decimal Identity_Col { get; set; }
The Entity Framework class file adds these lines of code to the Identity column.
Put these attribs on top of the property which is identity:
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
I encountered the same problem and error message in my AspNetCore 2.x application.
The only way I could solve it was by removing this line in the ModelBuilder.Entity method of the DbContext class:
// remove: entity.Property(e => e.Id).ValueGeneratedNever();
EF Code first: Because of an auto-increment PK 'id' field AND a guid column, design like this:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid FileToken { get; set; }
there was a duplicate identity. I changed it to:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
[DefaultValue("newid()")]
public Guid FileToken { get; set; }
and the problem went away.
In EF 6, there is a property of the field/column in your model for doing this:
StoreGeneratedPattern.
Set this to "Identity" in the property dropdown list.
(I don't know about EF 4. The above answer, using IsDbGenerated, seems to be for EF 4.)
And this corresponds in the underlying XML to an attribute to the element:
<Property Name="MyTableId" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
--but you don't need to deal with the XML manually, since you can use the designer.
How this gets messed up isn't clear. I had the problem even after refreshing my model from the database. Perhaps it gets confused if you set the PK on the table, or change its name, after you have already generated the model. (I am using the table/database-first approach, not code first.)
You can't use the above approach of putting the C# attribute on the entity code, because in this situation the entity code is generated by EF. EF is supposed to understand ("by itself") that the field is an identity.
I had this issue in my app; and got fixed it changing the property "StoredGeneratedPattern" of the id field to Identity.
So, Go to the model; look up for the table; click on propierties of the primary key fiel; and change the property.
See intercepting Entity Insert for generated always columns like StartTime and EndTime columns on history tables, rowversion columns as well.
I solved this by removing primary key in model from inserting data. because primary key auto increment.
var book = new Book
{
// Id = 1, //Don't need to write this
Genre = "Technology",
Author = "Charles Petzold",
Title = "Programming Windows 5th Edition",
Price = 30,
Publisher = "Microsoft Press"
};
_unitOfWork.Books.Add(book);
Well, You need give a value to ID, for example for the object Auto, just you should VarAuto.Id = 0;
After that you could do it something like this =>
using( MyContext db = new MyContext()){
db.Autos.Add(VarAuto);
db.SaveChanges();
}
That is the solution just give value to id, EF could be recognize the identity value in the table.
Just Try.
I'm using DB first and the table has identity column. I didn't use the db-scaffolding to generate this, I copied it from another entity and by mistake I took this property with.
So
Try to check the DBContext Class. I got this error, and the issue was with this property ".ValueGeneratedNever()"
I have just removed it and it works fine,
modelBuilder.Entity<TableName>(entity =>
{
entity.Property(e => e.Id)
//.ValueGeneratedNever()
.HasColumnName("ID");
});
Note: a moderator deleted this answer as a duplicate and left my other answer up, on a question with only the sql-server tag (which was the first question I arrived at from google). Since this question has the entity framework tag, posting the answer again here.
This is for EntityFramework Core 3.1.22. Using the wrong property to specify a foreign key causes Entity Framework to demote the primary key to ... something else. Entity Framework will then always attempt to insert an explicit value, which throws a database exception because it can't insert the value it's been told is a primary key and shouldn't be inserted.
Microsoft.EntityFrameworkCore.DbUpdateException: 'An error occurred while updating the entries. See the inner exception for details.'
Inner Exception:
SqlException: Cannot insert explicit value for identity column in table 'FOO' when IDENTITY_INSERT is set to OFF.
Code example. We have a 1-to-1 class mapping:
public class Foo /* child */
{
public int FooPrimaryKey { get; set; }
public int BarPrimaryKey { get; set; }
public virtual Bar PropertyBar {get; set; }
}
public class Bar
{
public int BarPrimaryKey { get; set; }
public virtual Foo PropertyFoo {get; set; }
}
modelBuilder.Entity<Foo>(entity =>
{
entity.HasKey(e => e.FooPrimaryKey);
entity.ToTable("FOO", "dbo");
entity.HasOne(d => d.PropertyBar)
.WithOne(x => x.PropertyFoo)
// wrong, this throws the above exception
.HasForeignKey<Bar>(x => x.BarPrimaryKey);
});
The foreign key should instead be (same key, different type):
.HasForeignKey<Foo>(x => x.BarPrimaryKey);
If you don't want to use EF core's auto-generating primary key values feature, you can turn it off. You can add your data to the primary key
It should resolve the error - Set Identity Insert off
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int StudentId { get; set; }
Setting Database Generation option to None helped me.
You can find more about it here- https://learn.microsoft.com/en-us/ef/core/modeling/generated-properties?tabs=data-annotations
Add this line in order to allow the Id column to receive 1,2,3 and 4 values instead of being auto-numbered.
Sql("SET IDENTITY_INSERT MembershipTypes ON")