I receive a large JSON having different recordsets in the form of arrays in a Xamarin-Forms application. The recordsets are linked with each other through reference Ids. Basically the data is coming from a relational database and I have to map the data into the device's local SQLite. I am using EFCore for that. I am able to successfully set up the Models and their FKs using OnModelCreating override. I have verified it by logging the table creation scripts. Now the issue is, when I AddRange a list of some records, EF Core automatically deletes some of the records. I don't know why and how.
Here is the screenshot in debugging:
The data is a huge graph of different relational records. Earlier I was trying to Add the whole graph by saving only the grandparent record. But there are several children who reference the same record more than once. For example, a UserType is referenced by many users. So EF throws Identity tracking issues. Then I decided to not save using the graph, instead save table by table. And now I am facing this issue. To be specific, there is a total of 11 tables involved in my saving. I am able to save 5 tables that have independent data e.g. UserTypes, EntityTypes, ContactTypes, etc. When I came to the 6th table which references some records of 5 saved tables, I am getting this issue.
Update:
I solved the problem. The issue was in a relationship that was wrongly defined. A WorkOrder can have one Customer only, but a Customer can be linked to many WorkOrders. I was taking it as One-to-One but was ignoring the other way. I updated the one-to-one to one-to-many in Customer entity and everything started working great!
By the way, this we can say the beauty and perfection of EF Core that it can never allow you to persist data against the rules you have defined. Though automatic deleting was a little confusing but ultimately that was my mistake.
Related
I'm setting up a data warehouse (in SQL Server) together with our engineers we got almost everything up and running. Our main application also uses SQL Server as backend, and aims to be code first while using the entity framework. In most tables we added a column like updatedAt to allow for incremental loading to our data warehouse, but there is a many-to-many association table created by the entity framework which we cannot modify. The table consists of two GUID columns with a composite key, so they are not iterable like an incrementing integer or dates. We are now basically figuring out the options on how to enable incremental load on this table, but there is little information to be found.
After searching for a while I mostly came across posts which explained how it's not possible to manually add columns (such as updatedAt) to the association table, such as here Create code first, many to many, with additional fields in association table. Suggestions are to split out the table into two one-to-many tables. We would like to prevent this if possible.
Another potential option would be to turn on change data capture on the server, but that would potentially defeat the purpose of code first in the application.
Another thought was to add a column in the database itself, not in code, with a default value of the current datetime. But that might also be impossible / non compatible with the entity framework, as well as defeating the code first principle.
Are we missing anything? Are there other solutions for this? The ideal solution would be a code first solution, or a solution in the ETL process without affecting the base application, without changing too much. Any suggestions are appreciated.
I'm using ASP.NET WebApi 2 and loading in part of a relational database structure into the front end website. This allows the user to make changes to multiple tables in a single store and to also view some extra data.
This mostly works pretty well. It means I can store changes to, say a person table and their related clothes and hair color on one call as follows:
db.person.Add(person);
db.SaveChanges();
The problem is that, I don't want to load all the related data. So where the shoe table may be loaded, I don't want the laces table to load with info about laces.
The issue I'm running into is that there is an attempt to store a duplicate shoe table to the database even though this was only loaded to allow the user to view these details. I imagine that this is because, I'm using [JsonIgnore] attributes to ignore certain parts of the object - it is thus recognizing this as a new object, when it isn't.
I could loop through the object removing any shoe information before call Add, but this would be slow.
Perhaps it is best to post a second object that only includes the items that have changed (after tracking these in the front end). Is there a better way?
When you use DbSet<T>.Add() in EF, the entity (or all the entitis in the tree, if it's an entity with related child entities) is attached to the DbContext as Added. That means that when you call SaveChanges EF will try to insert all the objects in the database. That's why you're getting duplication problems.
You need to learn how to work in disconnected mode with EF. Basically you need to track the state of each entity (i.e. control if they have to be inserted, deleted or updated), and set the correct state when you attach the entities in the context.
Look for docs on working with disconnected entities in EF, for example:
Persistence in Entity Framework
Add, Attach and Entity States
These will explain you how to handle disconnected entities.
I have an odd situation. I am working on a project with a very large existing database that is completely unrelated, but does contain corresponding table id's. It's as if someone copied the database but never related the tables.
In Entity Framework, is there a way to go EF code first and create the relationships in code, but Not apply those relationships in the database? I would like to go through and relate the database but the client doesn't want to pay to fix it.
Thanks!
In this instance, it seems you would be best to add relationships directly to your database (or to a duplicated database for testing/staging) and then just update your entities using your test connection and regression test your app.
Okay. assume I have structure:
School -> students -> StudentParents <- parents -> address
School can have many students, students can be relatives and have the same set of parents (may-to-many). Each parent can have multiple addresses.
Assume that students who have the same set of parents cannot study in different schools.
If given school_Id =5, I want to remove this school and all related records.
How to do this easily in Entity Framework 4?
Answer for your question would be same as this question.
You are trying to solve the problem in the wrong layer. You need to
reconsider your database design specially how you maintain the
referential integrity.
You need to set the "CASCADE DELETE"s of the foreign keys and reflect
that in your Entity Model. Then the database will make the necessary
changes to maintain the referential integrity when you delete that
entity.
Entity framework cannot delete data from database that is not instantiated as object in memory. This means you would need to load school data, all students data, all students parent data and so on, and then you would need to manually delete all the data.
This seems like a lot of work to do, so you may want to take another approach to this problem - delete all this data using stored procedure on database that is mapped to ObjectContext, this would perform better since you would not need to get all the data into memory.
But this also seems troublesome. The best approach would be to create Cascade delete constrain on database and map it also in entity framework's model. This has two advantages - you would need to only load school data and after it is deleted from model, it would be deleted from database and cascade delete would remove all referencing data. But if you have school and students data already in memory, EF will take care of marking those objects from memory as deleted, which will make your data consistent with database state.
The best resolution to this problem depends on whether you may or may not modify database. If you can - go for cascade delete. If you cannot - I would recommend stored procedure approach as better performing (assuming performance is an issue and there is lots of students, parents etc. in database).
I am using Entity Framework code first for the first time in a production environment. Everything went fine until we got the DB up and had put some of the data in it and then to get some of the data we were importing from another location we had to change field lengths. So we made some of the fields nvarchar(99) instead of nvarchar(50).
That went fine and the application still worked but I knew I needed to change the data annotation or it would blow up later when it loaded and tried to save a too long field. When I did that the app blew up even though the model and the db are now matching. So I thought that it was the hash in the metadata table so I thought I'd be clever and make a new DB and take the hash from there and copy it. That did not work and in fact now I cannot get my app to connect to the test db that we have data loaded in at all.
I do not want to drop and recreate this database. I want entity framework to realize that the model and the schema do in fact match. Is there any way for me to do this? Also why did copying the metadata from a DB that entity framework created with this model not work?
Entity Framework Code First creates a EdmMetadata table and saves a hash of your Model classes in it. When you change something in the Model, the hash of the new Model classes doesn't match what's in the EdmMetadata table anymore, and the app should "blow up" at runtime. What you need to do to keep using the same database without dropping it, is to delete the EdmMetadata table. This way EF will not do that check and will try to proceed with the access to the DB.
Check this video tutorial (skip to 8:10 of the "When Classes Change" section).
Sorry I fixed this. Removing the metadata worked. But turns out I had updated to a more recent version of EntityFramework accidentally while trying to fix my problem and this more recent version expected different naming conventions for the Database. In any case recreating the many-to-many group person table with a script from a DB created by Entity Framework and deleting the metadata fixed the problem.