EF Core repeatedly creating same migration, altering identity column and changing nothing - entity-framework-migrations

Recently I added a new data entity to my EFCore2.2 DbContext (within a net47 project) and attempted to generate a migration with the CLI tool as I have many times. On attempting to update the database the migration fails since the migration attempts to ALTER COLUMN on an identity column in an unrelated table. I removed the migration and removed the new entity and then ran add-migration, essentially with zero code changes. Sure enough, the same breaking AlterColumn calls, and nothing else, were generated (pointlessly, it seems) in the Up & Down methods. Here is the migration code:
public partial class ServerConfig : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<long>(
name: "ID",
table: "ProfileParams",
nullable: false,
oldClrType: typeof(long))
.OldAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<long>(
name: "ID",
table: "ProfileParams",
nullable: false,
oldClrType: typeof(long))
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
}
}
In the interest of eliminating extra factors, I reverted code back to just after this entity (ProfileParams) was originally added & migrations created. I tried add-migration from that point, and indeed, I got the same migration code as we see above (and no change in snapshot). I then reverted code back to just before the ProfileParams class was added, and generated the migration that actually created that table. It was identical to the full CREATE, and the snapshot was changed appropriately. But then I immediately ran add-migration again. Lo and behold I get the same extra "alter column" migration as above, and the next migration & the next will have it.
So essentially, going forward, it appears all future migrations will have this same "alter column" added in the up/down methods. Why?
In the interest of additional detail:
Various other tables have an ProfileParams navigation property which
EFCore picked up as a nullable foreign key.
Abbreviated bits of the snapshot:
modelBuilder.Entity("ProfileParams", b =>
{
b.Property<long>("ID")
.ValueGeneratedOnAdd();
b.HasKey("ID");
b.ToTable("ProfileParams");
});
modelBuilder.Entity("AssetUser", b =>
{
b.Property<string>("ID");
b.Property<long?>("ParamsID");
b.HasKey("ID");
b.HasIndex("ParamsID");
b.ToTable("AssetUsers");
});
modelBuilder.Entity("AssetUser", b =>
{
b.HasOne("ProfileParams", "Params")
.WithMany()
.HasForeignKey("ParamsID");
});

The problem is due to using uint for a primary key, and what looks like a bug in EF Core trying silently to work around this, and then silently failing in an obscure way.
In the case above, despite my detail I did not show the original entity class, but the ID in question was indeed of type uint. Answers to other questions suggest that EF Core does not support unsigned types, but it will certainly pretend to, and create a confusing situation such as this one! Instead of having an error on the initial migration (which does not apply the needed annotation for SQL auto-identity), it goes ahead and creates it.
This is what we would expect if the entity class simply had an ID of type long:
migrationBuilder.CreateTable(
name: "ProfileParams",
columns: table => new
{
ID = table.Column<long>(nullable: false)
/* But this part is missing when uint type is used! */
.Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
},
constraints: table =>
{
table.PrimaryKey("PK_ProfileParams", x => x.ID);
});
From there, and forever onward, on all future migrations it will attempt to fix its own omission by altering the column with the annotation. Oddly, though, even the "Down" function it generates suggests it already had the annotation since Up & Down are identical! But original migration and snapshot, and all subsequent snapshots fail to capture what the following migrations try to fix.
Presumably if the migration were tweaked and the table were actually dropped and recreated (not sure why EF Core thinks it can alter an identity column!) then the resulting SQL table would then have an auto-identity bigint key, but there would likely be issues populating the actual uint ID field from that value.
In short, just use a long key and it works. Wow.

Make sure you have NuGet package for only one provider.
I had (beside MSSQL) also MySql and Postgresql and it used the wrong one when using AddMigration.

Related

my sqlite3 DB doesn't show column values in device but it does in simulator

My DB is not getting copied over to my device, but it does to the simulator.
Here is what I am doing:
Create a new sqllite3 db from terminal:
sqlite> create table myTable (id integer primary key, name text);
sqlite> insert into myTable (name) values ('john');
sqlite> select * from myTable;
1|john
This creates a db in this path: users/John/iosApp.db
Then I close the terminal and copy that db to my xamarin project and set its buildAction to 'content'.
Here is my model:
[Table("myTable")]
public class MyTable
{
[PrimaryKey, AutoIncrementAttribute, Column("id")]
public int ID {get; set;}
[Column("name")]
public string Name { get; set; }
}
And I do this to copy the db to the Document folder:
string pathToDatabase = "iosApp.db";
userPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), pathToDatabase);
File.Delete (userPath); // delete first and copy next
File.Copy (pathToDatabase, userPath);
var myDB = new SQLiteConnection (userPath);
MyTable myTable = myDB.Get<MyTable> (1);
then I run the app and I set a breaking point after the last line in the code above and I hover over the myTable:
if I am using the simulator, I see the schema and value of 1 for ID and 'john' for Name.
if I am using the device, I see the schema but 0 value for ID and null for Name!
Looking at the path when I am using the device, points to this:
"/private/var/mobile/Applications/277749D4-C5CC-4BF4-8EF0-23B23833FCB1/Documents/iosApp.db"
I loaded the files in using iFunBox and the db file is there with the exact size
I have tried all the following:
Clean All in the project
Rebuild All
removed the 'debug' folder from the project
restarted Xamarin
and even restart the machine
But still the same behavior, what else should I try to be able to see the values of ID and Name?
my sdk version is attached
UPDATE:
After a lot of changes and cleaning up, I managed to display the value of all columns except the identity column displayed as 0. Puzzled, I went back to the xamarin sample project: http://developer.xamarin.com/recipes/ios/data/sqlite/create_a_database_with_sqlitenet/
it displayed the value of the identity correctly.
Trying to bring in similar code to my project, but no success.
To role out the possibility of version issue, I went and downloaded the latest sqlite from this link:
http://components.xamarin.com/gettingstarted/sqlite-net/true
The same behavior... I created a whole new page in my project, used the references the sample used and only has the code to create a sample table. Same behavior, the identity value is displayed in the other project but not mine. This leads me to conclude that there is something completely is wacky in my project. Now I am considering creating a whole new project and move my files to the new one after making sure first that the piece of being able to see the value of my id in my model shown up. Stay toned, I will make sure to update this thread.
If you have any pointers, please share them
I couldn't find a solution to my problem, but I found an alternate method to create the DB that turns out to be even nicer than the original one.
One important thing to note is that in the original problem (details above), the DB code was working for months since I started developing the application. I don't know when it started behaving badly, but I suspect it was due to the download of the new Xamarin 3.0. I can't think of any other reason.
So, to solve my issue, There are two main things I did:
I followed this link on how to create DB and tables and do CRUD operations: http://components.xamarin.com/gettingstarted/sqlite-net/true
This method seems to be the newest way to create DB. It was: published on
June 24, 2014. It has an SQLite.dll, whereas my previous solution was using a SQLite.cs file. So, now I am creating my DB now at runtime.
Something didn't work still with the new method. It was giving me an object null exception error. I didn't spend much time investigating about it. When I provided values for my primary key and identity values, the error went away. Actually, this could have been the solution to my previous problem. I would have tried providing the identity values against the old code, if I am not already happier with the new method.
I hope this helps someone.

Entity Framework 5 Migrations: Setting up an initial migration and single seed of the database

I have an MVC4 app which I've recently upgraded to Entity Framework 5 and I am trying to move our database over to using migrations from the development style of dropping and creating each run.
Here's what I've done in my app start function.
protected void Application_Start()
{
Database.SetInitializer(
new MigrateDatabaseToLatestVersion< MyContext, Configuration >() );
...
}
I ran the Enable-Migrations command on my repositories project and I thought that this would create an initial migration file however the only file it created was Configuration
When I delete the database it creates it as expected via code first and seeds the database from the Configuration file. In the configuration file I changed all the Add() functions to AddOrUpdate()
However it runs the seed function in my Configuration file each time the website starts and duplicates all the seed data again and again.
I imagined that it would create an initial migration file as the blog I read suggested that it would and I could put the seed data in there but it didn't
Can anyone explain how I should be setting up DB in code so that it only seeds once?
LINK: The migrations blog post I followed
While this is quite interesting for using the EF migrate.exe I've since switched to using roundhouse for running migrations. I still use EF to scaffold my migrations based on the models but I wrote a little console app to write the migrations out to SQL files. I then use roundhouse to perform the migrations themselves through my rake build scripts. There's a little more process involved but it's much more stable than using EF to perform the migrations on the fly when the application starts up.
This has proved to be a popular post so I have updated it in light of feedback from others. The main thing to know is that the Seed method in the Configuration class is run EVERY time the application starts, which isn't what the comment in the template method implies. See the answer from someone at Microsoft to this post about why that is - thanks to Jason Learmouth for finding that.
If you, like me, only want to run the database updates if there are any pending migrations then you need to do a bit more work. You can find that out if there are pending migrations by calling migrator.GetPendingMigrations(), but you have to do that in the ctor as the list of pending migrations is cleared before Seed method is called. The code to implement this, which goes in the Migrations.Configuration class is as follows:
internal sealed class Configuration : DbMigrationsConfiguration<YourDbContext>
{
private readonly bool _pendingMigrations;
public Configuration()
{
// If you want automatic migrations the uncomment the line below.
//AutomaticMigrationsEnabled = true;
var migrator = new DbMigrator(this);
_pendingMigrations = migrator.GetPendingMigrations().Any();
}
protected override void Seed(MyDbContext context)
{
//Microsoft comment says "This method will be called after migrating to the latest version."
//However my testing shows that it is called every time the software starts
//Exit if there aren't any pending migrations
if (!_pendingMigrations) return;
//else run your code to seed the database, e.g.
context.Foos.AddOrUpdate( new Foo { bar = true});
}
}
I should point out that some people have suggested putting the seed code in the actual 'up' migration code. This works, but means you need to remember to put the seed code in each new migration and its pretty hard remember so I wouldn't do that. However if your seed changes with each migration then that might be the a good way to go.
You could add a migration manually and fill it with whatever seeding code you want? In package manager console run:
Add-Migration [Name]
You can then edit that file which is created for you in your migrations folder.
In my project i actually do seeding like Richard though in the Seed method of the context configuration. I really have no preference. But migrations should be more efficient in that the application doesn't need to check if the rows exist in the database when the application starts. There is just the need to check if the migration has been run, which should be faster.
internal sealed class Configuration : DbMigrationsConfiguration<MyContext>
{
public Configuration()
{
// If you want automatic migrations as well uncomment below.
// You can use both manual and automatic at the same time, but I don't recommend it.
//AutomaticMigrationsEnabled = true;
//AutomaticMigrationDataLossAllowed = true;
}
protected override void Seed(MyContext context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data.
context.FontFamilies.AddOrUpdate(
f => f.Id,
new FontFamily { Id = 1, PcName = "Arial" },
new FontFamily { Id = 2, PcName = "Times New Roman" },
});
I'm using this in Global.asax:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// Any migrations that haven't been applied before will
// automatically be applied on Application Pool restart
Database.SetInitializer<MyContext>(
new MigrateDatabaseToLatestVersion<MyContext,
MyApp.Migrations.Configuration>()
);
}
}
This is something I've wondered about in the past too. I have certain tables in my database which get populated in my Seed event, and now I just check to see if one of them is empty within the Seed method. If there are rows, the Seed method doesn't run. Not infallible, but does the trick.
The answer to this SO question explains why Seed runs every time the app runs.
I use Jon Smiths method, but I have put the check for pending migrations statement in an #if block like this:
#if (!DEBUG)
if (!_pendingMigrations) return;
#endif
That way when I'm debugging the Seed method always runs to repopulate my seed data - useful when I do deletes during testing, etc. but I don't get the perf hit when in release.

Why am I getting a "Unable to update the EntitySet because it has a DefiningQuery..." exception when trying to update a model in Entity Framework?

While updating with the help of LINQ to SQL using Entity Framework, an exception is thrown.
System.Data.UpdateException: Unable to update the EntitySet 't_emp' because it has
a DefiningQuery and no <UpdateFunction> element exists in the
<ModificationFunctionMapping>
The code for update is :
public void Updateall()
{
try
{
var tb = (from p in _te.t_emp
where p.id == "1"
select p).FirstOrDefault();
tb.ename = "jack";
_te.ApplyPropertyChanges(tb.EntityKey.EntitySetName, tb);
_te.SaveChanges(true);
}
catch(Exception e)
{
}
}
Why am I getting this error?
The problem was in the table structure. To avoid the error we have to make one primary key in the table. After that, update the edmx. The problem will be fixed
Three things:
Don't catch exceptions you can't handle. You're catching every exception possible, and then doing nothing with it (except swallowing it). That's a Bad Thing™ Do you really want to silently do nothing if anything goes wrong? That leads to corrupted state that's hard to debug. Not good.
Linq to SQL is an ORM, as is Entity Framework. You may be using LINQ to update the objects, but you're not using Linq to SQL, you're using Entity Framework (Linq to Entities).
Have you tried the solution outlined here? The exception you posted is somewhat cut off, so I can't be sure it's exactly the same (please update your post if it isn't), and if it is the same, can you comment on whether or not the following works for you?
"[..] Entity Framework doesn't know whether a given view is updatable
or not, so it adds the <DefiningQuery> element in order to safeguard
against having the framework attempt to generate queries against a
non-updatable view.
If your view is updatable you can simply remove the <DefiningQuery>
element from the EntitySet definition for your view inside of the
StorageModel section of your .edmx, and the normal update processing
will work as with any other table.
If your view is not updatable, you will have to provide the update
logic yourself through a "Modification Function Mapping". The
Modification Function Mapping calls a function defined in the
StorageModel section of your .edmx. That Function may contain the
name and arguments to a stored procedure in your database, or you can
use a "defining command" in order to write the insert, update, or
delete statement directly in the function definition within the
StorageModel section of your .edmx." (Emphasis mine, post formatted for clarity and for Stack Overflow)
(Source: "Mike" on MSDN)
But You can Set primary Key in Model if use MVC Asp.net
Just Open model.edmx in your table ,go to your field property and set Entity Key = True

Cannot insert new Employee entity using InsertOnSubmit()

I'm facing this exception An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported. when I try to insert a new entity into my Employees table (the master one).
There is a relationship between the master Employees table and the details Orders table, and I'm sure that the relationship between these two tables (and specifically Employee.Orders EntitySet) is the cause of the problem since when I removed the relationship, it returns back to insert into Employees table with no problems.
When I searched for the problem, there was this blog post which I tried to implement but my case is a different than the one in the blog post in these items:
He faces the exception when tries to update (while I try to insert).
The tables architecture is different.
how can I solve this problem?
Here's the insertion code:
Employee emp = new Employee();
emp.Name = empName; // empName is a local variable
// What should I default emp.Orders to?
dc.Employees.InsertOnSubmit(emp);
dc.SubmitChanges();
P.S: My DataContext is defined on class-level in my repository and the exception is being thrown when I call dc.SubmitChanges();. and I didn't Attach any object why does it say that?
Here is an article explaining what you need to do using the Attach and Detach methods:
http://www.codeproject.com/KB/linq/linq-to-sql-detach.aspx
I am guessing it is trying to save something else besides just the employee object or you aren't showing us the full code in your repository. When you instantiate your DataContext object (dc) try setting DeferredLoadingEnabled = false, and ObjectTrackingEnabled = false and see if it works. If it does, try watching the SQL code in SQL Server Profiler and see if it is modifying other objects that may have came from a different context like the message says.
var dc = new MyDataContext()
{
DeferredLoadingEnabled = false,
ObjectTrackingEnabled = false
};
My bet is on the primary key.
Are you sure the primary key is also set on auto increment?
Did you
try changing the name, does it work then?
What happens if you remove
all rows from your DB? can you insert one then?

System.InvalidOperationException when trying to iteratively add objects using EF 4

This question is very similiar to this one. However, the resolution to that question:
Does not seem to apply, or
Are somewhat suspect, and don't seem like a good approach to resolving the problem.
Basically, I'm iterating over a generic list of objects, and inserting them. Using MVC 2, EF 4 with the default code generation.
foreach(Requirement r in requirements)
{
var car = new CustomerAgreementRequirement();
car.CustomerAgreementId = viewModel.Agreement.CustomerAgreementId;
car.RequirementId = r.RequirementId;
_carRepo.Add(car); //Save new record
}
And the Repository.Add() method:
public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
private TxRPEntities txDB;
private ObjectSet<TEntity> _objectSet;
public void Add(TEntity entity)
{
SetUpdateParams(entity);
_objectSet.AddObject(entity);
txDB.SaveChanges();
}
I should note that I've been successfully using the Add() method throughout my code for single inserts; this is the first time I've tried to use it to iteratively insert a group of objects.
The error:
System.InvalidOperationException: 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 stated in the prior question, the EntityKey is set to True, StoreGeneratedPattern = Identity. The actual table that is being inserted into is a relationship table, in that it is comprised of an identity field and two foreign key fields. The error always occurs on the second insert, regardless of whether that specific entity has been inserted before or not, and I can confirm that the values are always different, no key conflicts as far as the database is concerned. My suspicion is that it has something to do with the temporary entitykey that gets set prior to the actual insert, but I don't know how to confirm that, nor do I know how to resolve it.
My gut feeling is that the solution in the prior question, to set the SaveOptions to None, would not be the best solution. (See prior discussion here)
I've had this issue with my repository using a loop as well and thought that it might be caused by some weird race-like condition. What I've done is refactor out a UnitOfWork class, so that the repository.add() method is strictly adding to the database, but not storing the context. Thus, the repository is only responsible for the collection itself, and every operation on that collection happens in the scope of the unit of work.
The issue there is that: In a loop, you run out of memory damn fast with EF4. So you do need to store the changes periodically, I just don't store after every save.
public class BaseRepository : IRepository where TEntity : class
{
private TxRPEntities txDB;
private ObjectSet _objectSet;
public void Add(TEntity entity)
{
SetUpdateParams(entity);
_objectSet.AddObject(entity);
}
public void Save()
{
txDB.SaveChanges();
}
Then you can do something like
foreach(Requirement r in requirements)
{
var car = new CustomerAgreementRequirement();
car.CustomerAgreementId = viewModel.Agreement.CustomerAgreementId;
car.RequirementId = r.RequirementId;
_carRepo.Add(car); //Save new record
if (some number limiting condition if you have thousands)
_carRepo.Save(); // To save periodically and clear memory
}
_carRepo.Save();
Note: I don't really like this solution, but I hunted around to try to find why things break in a loop when they work elsewhere, and that's the best I came up with.
We have had some odd collision issues if the entity is not added to the context directly after being created (before doing any assignments). The only time I've noticed the issue is when adding objects in a loop.
Try adding the newed up entity to the context, do the assignments, then save the context. Also, you don't need to save the context each time you add a new entity unless you absolutely need the primary key.

Resources