Excplicit id values using EF Code-first and migrations - c#

I develop my ASP.NET MVC4 app using EF Code-first, also im using Migrations feature. I have specific entity and i want to set explicit id values for some reasons. How can i do this? I tried to mark id property with attribute like this:
public class NewsSource
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
public string Title { get; set; }
public string WebSiteUrl { get; set; }
}
Then i add corresponding migration, delete database and try to update database using Seed() method like this:
context.NewsSources.AddOrUpdate(x => x.Title,
new NewsSource {Id = 654, Title = "ABC", WebSiteUrl = #"http://www.abc.com/"},
new NewsSource {Id = 22, Title = "XYZ", WebSiteUrl = #"http://XYZ.ru/"});
And ive got this error: "Cannot insert explicit value for identity column in table 'NewsSources' when IDENTITY_INSERT is set to OFF". How can i set identity_insert to ON using EF and migrations. As i understood from many topics its impossible and i have to use direct SQL-commands. Am i wrong?

I had a problem when I tried to change a column to an IDENTITY field when it was originally not an identity field. See this question and this one. You have to remove the column and recreate it to remove IDENTITY so fixing up foreign keys etc is probably a step too far for Entity Framework to do in a migration. You will have to alter the Up() and Down() methods yourself, or you may get away with doing it in the database.

What happens if you remove the DatabaseGenerated attribute and just leave the [Key] attribute?
public class NewsSource
{
[Key]
public int Id { get; set; }
public string Title { get; set; }
public string WebSiteUrl { get; set; }
}
I ran into this issue awhile back and I believe this was a work around for me. I can't test it now since I don't have any projects in front of me with EF in them. All I can say is EF code first and the nuget migrations package is a great thing, if you treat it the way you are supposed to treat it. I have gotten myself into a number of WTF moments when using the two together and trying to seed complex related models. Good luck!

Related

Entity Framework creates non-existing column in query

I face the problem that EF creates a column in the query that does not exist in the Oracle database table.
The simplified model which is created by EF looks like this (I use DB first approach):
public partial class USER
{
public int ID { get; set; }
public string NAME { get; set; }
public int PROCESS_ID { get; set; }
public virtual PROCESS PROCESS { get; set; }
}
public partial class PROCESS
{
public PROCESS()
{
this.USER = new HashSet<User>();
}
public int ID { get; set; }
public virtual ICollection<USER> USER { get; set; }
}
I set up the foreign key constraint in the oracle sql developer.
When I try to get the Users for a selected Process like this:
var users = context.Users.Where(u => u.PROCESS_ID == 0);
It produces following error:
ORA-00904: "Extent1"."R1": invalid ID
So i took a look on the produced SQL:
SELECT
"Extent1".ID,
"Extent1".NAME,
"Extent1".R1,
FROM DB.USER "Extent1"
WHERE "Extent1".R1 = :p__linq__0
Of course this produces an error because R1 isn't a column in the table. But I can't figure out where it comes from. It seems like EF can't map the foreign key properly thats why it's also missing in the generated SQL query?
Maybe someone has a tip for me :)
To follow up my comment, here is a link to the conventions.
The convention for a foreign key is that it must have the same data type as the principal entity's primary key property and the name must follow one of these patterns:
[navigation property name][principal primary key property name]Id
[principal class name][primary key property name]Id
[principal primary key property name]Id
Your convention [navigation property name]_ID isn't on the list.
Encountered the same error recently while working with Oracle using DevArt provider. Turned out it was caused by a column name being longer than 30 chars. OP mentioned that the model posted in his question is a simplified one so it still may be the case.

Linq query deleting multiple rows instead of one. Very Simple Query

This should be really simple but I think I'm having possible issues with my model. I have been working with linq over a year and I should have this simple remove easily done. Please help! It's removing both records from the database when I only want one deleted
I have a database table with these properties.
Email, EmployeeName, StoreId
jsch#m.com,Joe Schneider,9
jsch#m.com,Joe Schneider,8
I need to delete Joe Schneider with storeId 9
So I run this simple query and remove process.
var temp2 = difference[i];
var PersonToRemove = db.Permissions.SingleOrDefault(s => s.EmployeeName == temp2 && s.StoreId == Persons.StoreId);
if (PersonToRemove.EmployeeName != null)
{
db.Permissions.Remove(PersonToRemove);
db.SaveChanges();
}
I am assuming one is going to say, hey your model is not right and don't put the name as a key, but I can't just be changing the model because other parts of the app are based on this model and would cause huge breaks. Could you give me advise how to edit the linq query to not delete both records?
model
[Table("Permissions")]
public class Permissions
{
[Key]
public String EmployeeName { get; set; }
public string Department { get; set; }
public int? StoreId { get; set; }
public String Email { get; set; }
}
[Table("Permissions")]
public class Permissions
{
[Key]
public String EmployeeName { get; set; }
}
The problem is here you are defining a primary key which has no length constraint on it. (MaxLength). This leads to EF generate a column with NVARCHAR(MAX). As mentioned here VARCHAR(MAX) columns are not allowed to be primary key. So correct definition should be like below
[Table("Permissions")]
public class Permissions
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)] <--
[MaxLength(255)] // <---
public String EmployeeName { get; set; }
}
Edit: You need to recreate the database in order to associated tables initialized with correct settings.
Edit 2 : Also you may need a DatabaseGenerated(DatabaseGeneratedOption.None) since its not identity column.
you can set Deleted state on individual entity like so:
var temp2 = difference[i];
var PersonToRemove = db.Permissions.SingleOrDefault(s => s.EmployeeName == temp2 && s.StoreId == Persons.StoreId);
if (PersonToRemove.EmployeeName != null)
{
db.Entry(PersonToRemove).State = EntityState.Deleted; // do this instead
db.SaveChanges();
}
EF should then figure out which entity you wanted to delete
UPD
I am assuming you are using EF6 and DB-first approach. I am also assuming you've got your DB context class set up with default convention model builder. It seems EF's default object tracking based on Key will not work as your key is not unique (this is a bigger problem, but I understand you're already aware of that).
You might try circumvent that convention by adding custom model builder configuration like so:
class MyDbContext : DbContext {
public virtual DbSet<Permissions> Permissions {get;set;}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Permissions>().HasKey(p => new { p.EmployeeName, p.StoreId});
}
}
since you didn't share your DbContext definition this is just a snippet but hopefully gives you some ideas to explore.
this is the API reference: https://learn.microsoft.com/en-us/dotnet/api/system.data.entity.modelconfiguration.entitytypeconfiguration-1?view=entity-framework-6.2.0

Cannot insert the value NULL into column 'MaintenanceId', table '<tableName>'; column does not allow nulls. INSERT fails EF 6.1

So i'm trying to do a simple add an entry to my db on azure but for some reason the db is not generating my PK for the entry.
Below is all the code used to create the db and do the entry.
This is on EF 6.1 on a console app
Context
public BlizzardDbContext() : base("AzureSqlDb")
{
}
public DbSet<Maintenance> Maintenances { get; set; }
Model
public class Maintenance
{
public Maintenance()
{}
public Maintenance(DateTime start, DateTime end, string info)
{
Start = start;
End = end;
Info = info;
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int MaintenanceId { get; set; }
public DateTime? Start { get; set; }
public DateTime? End { get; set; }
public string Info { get; set; }
}
Test that failed on save changes
var context = new BlizzardDbContext();
context.Maintenances.Add(new Maintenance() {Start = DateTime.Now, End = DateTime.Now, Info = ""});
context.SaveChanges();
I know it sounds so simple, i've used EF a few times before but cannot figure out what is going wrong this time
and here's the error
"Cannot insert the value NULL into column 'MaintenanceId', table '.dbo.Maintenances'; column does not allow nulls. INSERT fails.\r\nThe statement has been terminated."
Update: Ended up fixing this by deleting the db and recreating it, I think there was something weird going on with EF, it wasn't updating the db with the migration properly since after recreating it the column was then set to be Identity
Just verify whether the MaintenanceId is identity key or not in DB.
If it is not or you are not sure you can try below option
change
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
to
[DatabaseGenerated(DatabaseGeneratedOption.None)]
.None - That means "The database does not generate values."
Log on to your database and verify that the MaintenanceId is indeed auto-generating the key. EF supports this, and I suspect that something fun happened during migration, if you used that, or during the construction of the table.
Also, make sure that you have not disabled tracking of objects in your DbContext class. It is default on, so unless you explicitly disabled it, you do not have to worry about that one :)

ObjectContext Error with using .AddRange in EF 6

I'm trying to find some help on an error I'm getting when using the .AddRange in EF 6. I'm getting the following error.
The changes to the database were committed successfully, but an error occurred while updating the object context.
The ObjectContext might be in an inconsistent state. Inner exception message: AcceptChanges cannot continue because
the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are
unique before calling AcceptChanges.
As the error states, my records are actually getting added to the table so I don't know where fix the error.
Doing some research I found a bunch of posts where others say that it has to do with the .edmx file and a primary key on the table. Their suggestion is basically to add the PK and then rebuild the .edmx file. This doesn't fit my scenario for two reasons, one is that I'm using EF 6 with DataBase First so there isn't an .edmx file and second is that this is mapped to and Oracle 11 DB and so the identity is created with a trigger (which seems to work when I look at the added records).
Here is my code I'm using as well as the class for the entity.
using (APIcontext db = new APIcontext())
{
if (listLostTime.Count > 0)
{
db.GROUND_HOURS.AddRange(listLostTime);
db.SaveChanges();
}
}
And the entity class
[Table("GROUND_HOURS")]
public partial class GROUND_HOURS
{
[Key]
public decimal RID { get; set; }
[Required]
[StringLength(8)]
public string EMP_ID { get; set; }
[StringLength(2)]
public string COMPANY_CODE { get; set; }
public DateTime OCCURRENCE_DATE { get; set; }
[Required]
[StringLength(25)]
public string PAY_CODE { get; set; }
public decimal PAY_HOURS { get; set; }
public DateTime INSERT_DATE { get; set; }
}
I'm looking for any suggestions.
Decorate the RID property with the attribute DatabaseGenerated( DatabaseGeneratedOption.Identity )
The problem is that entity framework isn't updating the key value RID with the store generated value prior to accepting changes. In your case, with multiple GROUND_HOURS entities created, each will (presumably) have the default RID value of 0. When EF attempts to accept changes, it recognizes than more than one entity has the same key value and complains.
Thanks to #Moho who gave the ultimate fix. This is how I changed the primary key in my entity class to work and is what I used in my application.
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int RID { get; set; }
I was also able to fix it another way just to let others know. First off because this is and Oracle DB the RID (which is my Primary Key) was scaffold as a Decimal. That caused the RID to always be a 0 when I added my object to a list without specifically assigning it a value. To work around that I changed the RID property to an nullable INT and then when I created my list I set the RID=NULL.
[Key]
public int? RID { get; set; }
This is what I did when created my list.
foreach (var item in results)
{
GROUND_HOURS lostTime = new GROUND_HOURS();
lostTime.RID = null;
lostTime.EMP_ID = item.EmployeeId.ToString("D8");
lostTime.COMPANY_CODE = item.CompanyCode.Trim();
lostTime.OCCURRENCE_DATE = item.OccurrenceDate;
lostTime.PAY_CODE = item.PayCode.Trim();
lostTime.PAY_HOURS = item.Hours;
listLostTime.Add(lostTime);
}

Error While Enabling Code-First Migrations On Mobile Services Database

I have an Azure Mobile Services project (C# backend) that I recently created and attached to an Azure SQL database. I have been trying to enable Code-First Migrations on that backing database, but it throws errors when I try to update the database.
I ran through all of the conventional steps to enable migrations (Enable-Migrations, Add-Migration). But when I try to Update-Database, it returns the following error:
Cannot create more than one clustered index on table 'dbo.Appointments'. Drop the existing clustered index 'PK_dbo.Appointments' before creating another.
Why is this happening? There aren't any tables in my database, and the project is pretty much the default.
Several of the answers about deriving from a custom entity class will work, but they are not the ideal solution. As the EF team (and others) have mentioned, you need to simply add this line to your Context Configuration constructor.
SetSqlGenerator("System.Data.SqlClient", new EntityTableSqlGenerator());
This will remove your errors when creating migrations and allow you to update the database via powershell command.
If you are getting this error on update-database after creating the migration class, Then have a look # your migration class. The migration class will take primary is clustered index. So remove that from the up() method.
.PrimaryKey(t => t.Id, clustered: false)
.Index(t => t.CreatedAt, clustered: true);
If you using it on azure mobile service, do not call 'update-database' manually.
refer http://azure.microsoft.com/en-in/documentation/articles/mobile-services-dotnet-backend-how-to-use-code-first-migrations/
I was fighting with this problem today for a few hours. Until I found this link:
How to make data model changes to a .NET backend mobile service
If you follow the instructions there, it will definitely work. The main thing is, that the migration will take place, when you hit F5 during a local debugging session.
I just had the same issue.
It is caused by the definition of EntityData that is our base class:
public class OrgTest : EntityData
{
public string Prop1 { get; set; }
}
I replaced EntityData with my own implementation "CustomEntity" where I removed the attribute [Index(IsClustered = true)] on the CreatedAt column:
public abstract class CustomEntity : ITableData
{
// protected CustomEntity();
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[TableColumn(TableColumnType.CreatedAt)]
public DateTimeOffset? CreatedAt { get; set; }
[TableColumn(TableColumnType.Deleted)]
public bool Deleted { get; set; }
[Key]
[TableColumn(TableColumnType.Id)]
public string Id { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
[TableColumn(TableColumnType.UpdatedAt)]
public DateTimeOffset? UpdatedAt { get; set; }
[TableColumn(TableColumnType.Version)]
[Timestamp]
public byte[] Version { get; set; }
}
and now I inherit from this one:
public class OrgTest : CustomEntity // EntityData
{
public string Prop1 { get; set; }
}
Probably I will have troubles further on, but for the time being I can create my model!
Hope you can also start like this!
See this article:
avoid nightmares using ef first migration in azure mobile services
EntityData define a cluster indext to CreateAt and Id is by default a cluster index, this way it provide an error and you should define only one.

Categories

Resources