Using EntityFramework code-first, I've created a simple Foo table. Here's my entity:
public class Foo
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public virtual string Id { get; set; }
public virtual string Name { get; set; }
}
However whenever I try to insert a new row, I get a Cannot insert the value NULL into column 'Id'. Why is this happening when I've added a DatabaseGenerated attribute? Deleting and recreating my table makes no difference.
Identities for string column types are not supported with SQL Server. (How do you expect such a string to look like?) To get this working you could - for example - add a computed column/user defined function in SQL Server that formats a string from an ordinary int identity column - as shown here.
you forgot the Key attribute. and there is no need to use virtual for primary key.
as mentioned by Slauma you can't use Identity for string datatype.
Try this code:
public class Foo
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public virtual string Name { get; set; }
}
For anybody reading this in 2020, 'Identity' attributes for string column types are supported using Entity Framework. For example, decorating a string type property in your C# class with the [DatabaseGenerated(DatabaseGeneratedOption.Identity)] attribute tag, then letting Entity Framework create the table through a database-first migration, and inserting that record through your program with Entity Framework methods (AddAsync(), SaveAsync()), auto-generates a string that looks like e.g. 'b652daab-9bb9-5143-a1ae-97a89232ea38'.
MS SQL Server will not auto generate this value however (I trialled it with an Insert SQL statement). Instead, the program / Entity Framework seems to generate it.
I know that is an old thread, but for anyone in the future:
DatabaseGenerated(DatabaseGeneratedOption.Identity)
does not generate any values, it simply let EF know that DB suppose to generate the value as described in the MS documentation. Therefore you must either set a default value in the database, in your model or assign an actual value in the controller.
As Treadmeister stated, identity is working fine with string Id with at least Entity Framework Core 3+. My problem was passing an object from Web App with Id: "" which is string.Empty not null so EF Core was not generating new Id
Related
I have a quick question and looking for the best way to do this, whether EF has the capability or not, am not sure? I am using EntityFramework 6.3.
I have the following parent-child scenario,
public class Application{
[Key]
public int ApplicationId {get;set;}
public string Name {get;set;}
public string Status {get;set;}
public virtual List<Document> Documents {get;set;}
}
public class Document{
[Key]
public int DocumentId {get;set;}
[Index("IX_ApplicationDocument", 1, IsUnique = true)]
public string DocumentType {get;set;}
[Index("IX_ApplicationDocument", 1, IsUnique = true)]
public string Name {get;set;}
public int ApplicationId {get;set;}
[ForeignKey("ApplicationId")]
public Application Application {get;set;}
}
So an application is made to a department, and stored in the database, each application has a status and when submitted, status of pending, because various validation has to occur before it is approved. When an application is rejected, the submitter has to make a new application (please note I used a minimalistic example than what it actually is), however, the applicant may submit the same documents again. The problem is, this already exist in the system and can not be duplicated. As you can see, the second time they attempt to submit it will throw a constraint exception. How can I overcome this using EF, is there a way to create a constraint based on the parent's status, or is this something that can only be done programmatically?
Dont know if its helps you in your case or not, but check this out
Assuming your entity is defined as
public class Entity
{
public int Id { get; set; }
public int Parent { get; set; }
public int Child { get; set; }
}
Following fluent API code will create index as you desire:
modelBuilder.Entity<Entity>().HasIndex(p => new {p.Parent, p.Child})
.HasFilter("isdeleted = 0")
.HasName("unq_t_parent_child");
SQL generated
CREATE INDEX [unq_t_parent_child] ON [Entity] ([Parent], [Child]) WHERE isdeleted = 0;
HasIndex defines index over properties in the table Entity
HasFilter allows you to set a filter for your index. This value is sql so you need to make sure you are writing correct sql syntax.
HasName configures the name of the index.
(If you map Entity to table t & the properties to their column names, migrations will create exactly same sql as you want.)
Also a check constraint is different from unique index. If you are looking to add check constraint then you need to use migrationBuilder.Sql in your migration file.
So unfortunately I have searched around and there is no solution for this for EF 6. The best way I can do this was following the guidance of the following article, where you manually add the Filtered Index in your migration after table creation.
Blog
I am trying to insert a new row to my table, using EF Core, SQL Server and C#, but I am having trouble getting EF Core to use the identity column properly.
Here's what I am doing:
I am creating a new object using the Entity Framework generated class (I've included the entity class definition at the end of my post)
EmployeePermissions employee_permission = new EmployeePermissions
{
FkEmployee = PkEmployee,
FkPermission = permission_key
};
Then I call db.EmployeePermissions.add(employee_permission), which works on all of my calls where an object comes from [FromBody] <Entity Class> <object_variable> (albeit using other tables).
But here, when I instantiate the class myself, I get this error:
SqlException (0x80131904): Cannot insert explicit value for identity column in table 'Employee_Permissions' when IDENTITY_INSERT is set to OFF.
I don't understand why this is happening — I want it to auto increment the identity column. I used ObjectDumper to see what is getting passed to .Add(), which is as follows:
properties {
PkEmployeePermissions = 0 [System.Int32] // this is the identity column, of course
FkEmployee = 31 [System.Int32]
FkPermission = 6 [System.Int32]
FkEmployeeNavigation = <null>
FkPermissionNavigation = <null>
}
I have investigated the other calls which are working fine (the ones where [FromBody] creates an object) and the identity column simply equals 0 in those calls too, so I don't understand what is different here.
Have I misconfigured something in the database? I have double checked in the column properties that the column PkEmployeePermissions is indeed an identity column, so it should be auto incremented.
Here's the Entity class if it helps:
public partial class EmployeePermissions
{
public int PkEmployeePermissions { get; set; }
public int FkEmployee { get; set; }
public int FkPermission { get; set; }
public Employee FkEmployeeNavigation { get; set; }
public Permission FkPermissionNavigation { get; set; }
}
It turned out I had updated the primary key column, PkEmployeePermission to be an identity column and forgotten to re-generate the database scaffolding using EF Core.
The root cause of the problem was that inside of the OnModelCreating() method (in the generated database context file) the field PkEmployeePermission had the method .ValueGeneratedNever() called on it, which meant that even though it was a primary key, EF Core did not automatically generate an incremented value for that column. By commenting out that method in the database context file, the code worked properly.
The default convention is for the primary key of a class to be called either Id or (classname)Id - this is not the case in your class.
Also: if you're mapping to an IDENTITY column in SQL Server, you must add a relevant data annotation to the key column.
Try this:
public partial class EmployeePermissions
{
// add the [Key] annotation to indicate the primary key of the class/table
[Key]
// add the [DatabaseGenerated(..)] annotation to indicate an IDENTITY column in the table
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int PkEmployeePermissions { get; set; }
public int FkEmployee { get; set; }
public int FkPermission { get; set; }
public Employee FkEmployeeNavigation { get; set; }
public Permission FkPermissionNavigation { get; set; }
}
Now you should be able to insert those objects, and have them stored properly in your SQL Server table.
I'm new to Entity Framework, just a question on how EF generate insertion SQL for entity class that has default 0.
This is the data model class:
public class Product
{
public long ProductID { get; set; }
public string Name { get; set; }
}
and the underlying table Products in Sql server has identity column on ProductID .
So let's say a controller that use model binding to create a Product object p1, and then we do:
context.Products.Add(p1) //p1.ProductID = 0 for default
context.SaveChanges();
My questions are:
Does EF need to send a query to database to get latest primary key in Products table and then plus 1 to be p1.ProductID? Isn't that very inefficient as you need to query database for latest existing primary key and then send another insert SQL to insert record?
what does the Dbset<Product>.add() method really mean? I mean if the object's id is 0, we know it doesn't exist in the database (if id > 0 then we know we are modifying existing record), can't we just add newly created p1 to the database, why we still need to track it?
1.) no, you dont need to get latest object's primary key to determine next Id.
2.) Primary Key starts from 1 not 0,in EF if you use default identity provider as explained below, EF can manage Primary Key auto, so no need to set ANY number to that variable. Then, context.Products.Add(p1) adds value to Local Table (in RAM), after addition context.SaveChanges(); will trigger to send Local Values to SQL Database.After SaveChanges you will see correct Id of value
there is a feature to generate auto Id for tables.
firstly, you should select which property is Primary Key with [Key] attribute.
Secondly, you should determine the type of Primary Key whether Integer or String (string has no auto Id Generator)
Then, if it is Integer and you need auto Id generator, you should use [DatabaseGenerated(DatabaseGeneratedOption.Identity)] to auto generator.
After that, you dont worry about value of ProductID EF can manage it.
public class Product
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long ProductID { get; set; }
public string Name { get; set; }
}
not: if you want string Primary Key (or manually add Id) you should use [DatabaseGenerated(DatabaseGeneratedOption.None)]
more examples about EF (select EF version from navigator)
I have a stored procedure in my sqlserver database which is returning multiple resultset.
I am using following link from msdn to read multiple resultset from SP in entity framework.
https://msdn.microsoft.com/en-us/library/jj691402(v=vs.113).aspx
To read data, I need to have DBSets in xyzDBContext class for each of the resultsets.
Model Class:
public class AreaView
{
public String Area { get; set; }
public String Weight { get; set; }
}
DBContext:
public class EnsembleAPIContext : DbContext
{
public DbSet<AreaView> area {get; set;}
// I want to prevent this table from getting created in db
}
This is how I am reading resultset and mapping it with above created dbset.
reader.NextResult();
var contributionArea = ((IObjectContextAdapter)db)
.ObjectContext
.Translate<ContributionArea>(reader, "area ", MergeOption.AppendOnly);
What I need to do is I want to create entity for these resultsets, but I dont want framework to create tables for these entities in database.
Note: Reason for doing this is, resultset which is returned by sp doesnt have a primary key, so suppose we can have a valid table created using entity without PK.
Is this possible?
Any help is appreciated.
The answer to "If we can skip creating tables in database with Entity framework is": Yes
Use [NotMapped] attribute.
[NotMapped]
public class Employee
{
public int ID { get; set; }
public String name { get; set; }
}
You can use this model for general purpose and table wont be created for this in database.
Another way of doing this is
In OnModelCreating() method
modelBuilder.Ignore<Employee>();
This way DBContext will ignore creating table for this model.
Can we create a DBSet<> without creating corresponding table in database
No. DbSet<T> represents a real database table or view.
To read data, I need to have DBSets in xyzDBContext class for each of the resultsets.
You don't. The ObjectContext.Translate method can be used to map DbReader to any class. The linked example is using entity types, but there is another Translate method overload which works for any type as described in Directly Executing Store Commands MSDN topic - Materializing the Result Type section.
With that being said, remove the DbSet from your context and use something like this:
var areaView = ((IObjectContextAdapter)db).ObjectContext.Translate<AreaView>(reader);
Edit: I'm so sorry I wasted your time. I missed a line of code when debugging that was causing this problem. Someone had put a conditional that was checking if the name already existed in the database and threw this exception if it was.
I am using Entity Framework code first and I have an entity which contains an index with a unique constraint across two columns as shown in the code below. (I changed the names of properties to generic things so as to not show any of my company's code base)
[Table("TB_Table")]
public class Table : IEntity
{
[Key]
[Column("TBT_RID")]
public int Id { get; set; }
[ForeignKey("Something")]
[Index("idxSomethingTableName", 1, IsUnique = true)]
[Column("TBT_SOS_RID")]
public int SomethingId { get; set; }
[Index("idxSomethingTableName", 2, IsUnique = true)]
[MaxLength(255)]
[Column("TBT_Name")]
public string Name { get; set; }
// Navigation properties
[JsonIgnore]
public virtual Something Something { get; set; }
[InverseProperty("Table")]
[JsonIgnore]
public virtual ICollection<AssetTag> ObjectTables { get; set; }
}
When inserting a record in SQL, the unique constraint is being enforced properly. Then, when trying to enter a record through Entity Framework, it tells me that it cannot add a record that has a different "SomethingId" value, but the same "Name" as another record.
For example, I can insert these records with SQL:
insert into TB_Table (TBT_SOS_RID, TGT_Name) values
(1, 'A'),
(1, 'B'),
(30, 'A')
But then I cannot add another (1, 'A') with SQL. Okay, great. The constraint is working correctly. Now, if I try to insert a record using entity framework with the values (30, 'B'), I should be able to do this, because the TBT_SOS_RID (SomethingId in C#) is different. Instead, I get an InvalidOperationException with the message "Invalid table, table already Exists". This happens on the DbSet.Add() method, before calling the SaveChanges() method.
Can you think of any reason why Entity Framework would think that this is a violation of the unique constraint when SQL does not?
It appears that Kryptos answered a similar question on how to handle composite indices with foreign keys here: Composite Indices with Foreign Keys
I've not tested the solution, but it might help lead you down the correct path, expanding on the answer by niaher in the same question.
You decorated Name as follows:
[Index("idxSomethingTableName", 2, IsUnique = true)]
[MaxLength(255)]
[Column("TBT_Name")]
public string Name { get; set; }
As far as Entity is concerned, you have stated that Name must be unique, therefore, you cannot enter two names that are the same.