I have the problem that my database can contain invalid values that come from a previous version of the software. For these values we have to decide individually how to handle them.
I have created a corresponding Entity Framework that can be used to access the database. Internally on the test systems everything worked as well, but during the first test installation on a customer system the program always crashed due to the invalid values in the database.
Now the question is can I detect the errors in the database using the Entity Framework?
I would like to know in which records, which columns lead to errors.
I can't assume any Keys to get each Entity on its own. So my first idea was to check each repository (DbSet) from the DbContext for each entity (QueryingEnumerable). However, with DbSet you can't really access a single entity, you can only go through the query until the first error occurs.
Also, I still don't know which columns led to the error since the exceptions don't contain any information.
Any suggestions what else I can try?
If you have ids or keys for given entities held by dbSet, then you can get single entity.
// In repository or somewhere else, where you have access to this particular DbSet
DbSetOfSomeEntity.FirstOrDefault(x => x.Id == /* Some id number, guid etc */)
Access them in try-catch block, read exception and decide what to do next.
Related
What is the best practice to handle the following situation?
It is known that many records (thousands) will be inserted with a fair possibility of a primary key exception. In some cases the exception should trigger some alternative queries and logic. In other cases it doesn't matter much and I merely want to log the event.
Should the insert be attempted and the exception caught?
or
Should a query be made to check for the existing record, then attempt the insert if none exists?
or Both?
I have noticed slightly better performance when merely catching the exception, but there's not a significant difference.
IMO It depends. If the client is responsible for generating a PK, using a UUID or Snowflake etc. where keys are expected to be unique then the first option is fine. Whether you bother with a retry after generating a new ID or simply fail the operation and ask the user to try again (as it should be a 1 in a billion exception, not the norm) is up to you. If the data is relying on sequences or user-entered meaningful keys it should be managed at the DB side using DatabaseGenerated.Identity and meaningless keys with related object graphs created and committed within a single SaveChanges call.
The typical concern around ID generation and EF is usually where developers don't rely on EF/the DB to manage the PK and FKs through navigation properties. They feel they need to know the PK in order to set FKs for related data, either saving the primary entity to get the PK or generating keys client-side. One of the key benefits of using an ORM like EF is giving it the related objects and letting it manage the inserting of PKs and FKs automatically.
There are couple of things over here.
One thing required is that you must have primary key vonstraint on column at the database Level
Now at the Entity Framework level, it is good if you check whether the record exists or not. So basically what happen you query for record using primary key and if it is found, then it return the entity and then you make changes to entity and at last SaveChanges will save that entity
Now if you are not able to find entity then you have to add entity
If you try without query then it is problematic for EF and specially if multiple request try to update same record
Now one more case is that, lets assume that there is possibility that multiple request can insert same record and so primary key constraint will help here and it will not allow duplication if you are generating primary key manually
For update too, there is possibility of data loss if you are not taking care of concurrency
I use a third party database with Entity Framework 6. This works fine; however, when a table within my model is changed (three columns were deleted), my program throws an exception:
System.Data.SqlClient.SqlException: Invalid column name '<deleted column>'
I don't use any of these columns. I only read them from the database.
I can update my model, but then when there is another change in a table, my program will crash again. How can I modify my program so that it won't crash on the next database change?
You can use a Code First approach starting from database (generate classes from database). At the end of class generation you can delete entities that you don't need (i.e. entities related to all unused tables) or properties related to unused fields.
Disable migrations.
You can also delete intermediate files generated by EF code generation (files different from .cs files).
At this point, any changes to database that not affects mapped classes/properties does not cause errors in EF.
Create a context with only the entities you need. Create entities with only the properties you need.
see EF code first.
Use Fluent API to specify primary keys and more.
It will still crash though if any of your entities/properties gets changed/deleted
I am using Entity Framework to save some data in a SQLite database file.
This is my table in DB file
ID Name Username Pwd
ID is autoincrement, and rest of columns are of Text type
This is how I am saving my data into the database:
UserInfo userInfo=new UserInfo();
userInfo.Name="abc";
userInfo.Username="xyz";
userInfo.Pwd="123456";
using (var context = new ApplicationContext())
{
context.UserInfo.Add(userInfo);
context.SaveChanges();
}
The problem is, this code is not inserting any new row into the table. I also tried this before saving, but no luck
context.Entry<UserInfo>(userInfo).State = EntityState.Added;
context.ChangeTracker.DetectChanges();
I tried debugging and no exception is occurring.
How can I insert new row into a table using Entity Framework?
Possibilities that may cause an issue.
Right Click on your Entity Data Model and Update Model From Database. To make sure you have updated till the last change.
Make sure you are looking at the correct Database and Table. Every one makes this mistake once in a while.
Make sure you are using the valid connection string. Pointing the proper databases. Make sure its not a old db / some other backup db.
Make sure you are using the proper entity which is up to date.
The above code you have, its perfectly working fine to me. I just did a workout to sort out this issue.
The above points are guesses.
Refer this Link Entity Data Model Example & One More Example Code available here
I had a similar problem once and it can be a pain to determine what exactly causes this. One issue that might be causing such a behavior in EF is having multiple instances of the Context object such that when you call SaveChanges on your Context, you are actually calling it on a different instance than the one you added the entity on (and EF does not detect any changes in the entities or the new entity is not attached to the right context, causing SaveChanges to not send any SQL requests to the database).
I suggest debugging this in VS (using the object id feature) in order to see if you have multiple context instances. Using the Unit Of Work pattern together with repositories is a way to have a better control over the lifetime of the context objects in your application
It is mentioned on this MSDN link the following about the .Find() method
If the entity is not found in the context then a query will be sent to
the database to find the entity there. Null is returned if the entity
is not found in the context or in the database. Find is different from
using a query in two significant ways:
• A round-trip to the database
will only be made if the entity with the given key is not found in the
context.
• Find will return entities that are in the Added state. That
is, Find will return entities that have been added to the context but
have not yet been saved to the database.
But can this cause a problem? Let's say that an object was marked as Added state, but before saving it to the database an exception occurred. So the find might return the object with Added state, which have not been saved to the database later on.
Second concern, what if the .Find found an object in the context and that object was updated in the database just after finding it, so the object version on the context will be old?
So what are the benefits I can get from using .Find() instead of doing my search based on the primary key using .Where or .firstordefault(a=>a.primarykey ==id)?
Well the docs state that Find...
Uses the primary key value to attempt to find an entity tracked by the context. If the entity is not in the context then a query will be executed and evaluated against the data in the data source,
So it searches the cache first. If what's in your cache is old (or doesn't exist in the database - and maybe never will) then that's what you get. It ONLY does a query if it can't find the entity in the cache. I wouldn't say it returns the "wrong" thing because of what it's defined to do. If you need to find data that might be changed by another user or that's guaranteed to exist in the database you'll want to stick with a query.
Im getting this error:
The model backing the 'database' context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).
But the problem is that my entities are the same as in the database: same maxlength, if null, same data type.
The error occurs when i update my model, since the database and the model have not the same attribute. But my question is. Is there any other case that this error could occur? It says that the error is in this code:
int UserId = (from d in db.Tbl_Users
where d.dbUserID == userName && d.dbPassWord == pass
select d.dbUser).SingleOrDefault();
Everything is its ok, the tables attribute are totally the same(database and model) but when i run the app, the error fire. So, ill repeat the question, When does the error migrations occur? Is there another escenario that the error fire??
It's giving you the error there because it's the first time that you're using the DbContext in your application to call the database. Whenever you ask for database records for the first time in the application Entity Framework will automatically check to see if the model that the DbContext generates is the same as the one already found in the database. Not the database tables themselves, but the model that is stored in the database. When it notices that they are different it automatically throws that exception.
To avoid it you'll need to set some sort of initializer to tell Entity Framework what to do if the models don't match. If you're using migrations it would probably look like this (do this before the first time you call for the context):
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDbContext, Configuration>());
There are also other initializers to use, like DropCreateDatabaseAlways and DropCreateDatabaseIfModelChanges, but I much prefer the migration one.
This must be the first time you're using the DbContext class (i.e. connecing to the DB), so that is when the internal data model is built and compared to the database schema.
Edit: you can delete the contents of dbo.__MigrationHistory if you're not using migrations and want to quickly see if it solves the problem.