I have read over several other questions about this, but I haven't been able to get it to work for me.
I'm using EF Code First, I have two entities Room and Equipment with a many-to-many relationship. It's correct in the DB with an intermediate table that contains a foreign key to both the Room and Equipment tables. However, I haven't been able to get an insert to work.
var room = roomService.FindById(roomId);
var equipment = service.FindById(equipmentId);
//do I need to do both of these?
room.Equipment.Add(equipment);
equipment.Rooms.Add(room);
db.SaveChanges();
This doesn't work at all. I have also trying using Attach to attach both the relevant entities to the context based on advice in other questions but it just seems to stop the code from running. Also, I tried manually change the EntityState to Modified and that didn't help either.
Any ideas?
Related
I am trying to call a linq query in asp.net 5. However, my query results in an infinite loop of data between two tables.
Logs (logs_historical)
meterID (FK)
log_data
-----
Meters
meter_uid (PK)
My goal is to have multiple logs related to one meter.
Relationships
Foreign key Base Table = logs
Foreign key Column = meterID
Primary Base Table = meters
Primary Key Colum = meterID
This is my linq query
records = dbContext.logs.Where(e =>(e.timestamp.Value.Month == inputDate.Month)).ToList() ;
1) This screenshot shows the table information and (foreign key table)
When I look into the foreign key table information, it also has the logs.
Going into the logs will show the same table from picture (1)
2)
I'm sure this was asked before, but I do not know what this problem is called. I am new to databases. Thanks for any advice!
As a quick fix, you can probably use dbContext.Configuration.LazyLoadingEnabled = false;
just before your query. You can disable it globally as well.
What happens is Entity Framework will eagerly load all related entities. If you have entities that go several levels deep, or that reference each other, well, as you have experienced, it will continue to follow those relationships. Disabling lazy loading will prevent this. Please note that you will have to explicitly declare anything you want included via the .include() function.
The other option is to redesign your database so that this isn't the case, but sometimes that just isn't feasible. I don't really know the intricate workings of your project, so I am speculating here.
EDIT:
I forgot to add, if you go into the model browser and explore the models that were created for you by Entity Framework, you will find those relationships that are causing the issue. If you are using code first, you can easily fix this. If you are using database first, you are somewhat at the mercy of how EF interprets relationships.
In my School EF Model, I have Kids and Tutorials in many-to-many relationship.
Let's assume both Kids and Tutorials have existing items in them, now we just want to change their existing relationships. That is, to add/delete some tutorials from a kid.
var kid; //the request target to modify relationships
//kid.Tutorials has the old existing relationships to be modified by add/del
var tutorialsToAdd; //the request to add relationships
var tutorialsToDel; //the request to del relationships
using (var conn = new SchoolEFModels(efConnectionStr)) {
conn.Kids.Attach(kid);
kid.Tutorials.ForEach(t => conn.Tutorials.Attach(t));
kid.Tutorials.AddRange(tutorialsToAdd); //simple add extension in batch
kid.Tutorials.RemoveRange(tutorialsToDel); //simple del extension in batch
conn.SaveChanges();
}
When I do this, I got an exception saying:
"Cannot insert duplicate key in object 'dbo.Tutorials'. The duplicate key value is (10)."
I can see EF is trying to create new Tutorial items instead of updating the existing relationship for me. Which is what I don't want. You misunderstood me EF!
What is wrong with my code? How do I make it update Many-to-Many relationships?
I figured it out.
Adding/removing it will make EntityState turn to Added/Deleted. Therefore, causing it to reinsert existing Ids as the article mentioned, thank Gert there for the link.
So, if you modify each of the conn.entry(kid/tutorials).State to EntityState.Modified and then call conn.ChangeTracker.DetectChanges(); then conn.SaveChanges(); it will only update the many-to-many table as expected.
UPDATE:
One thing you need to be careful tho. If the in-memory objects list of Kids and Tutorials are linked to each other. e.g. Kids[0].Tutorials[0] == Tutorials[0] && Tutorial[0].Kids[0] == Kids[0] EF will not be able to handle this dead loop for you. You need to break this circular link first.
To do so, my approach is to open a Connection and read the Kid out Includes(Tutorials), and then use the result to update many to many relationship, but not to use the in-memory objects.
I´m wondering if its possible to work with one object in Entity Framework and when I update the principal, EF creates or updates the lists, Let me show one example:
Objects Relation (image: http://i.stack.imgur.com/GJ2FW.png)
In this example, we have a Companie with a list of Employees with has a list of addresses and phones. If a create one Company, in disconnected mode. After that I will add some Employees with Addressees and Phones, It´s possible, like NHibernate, send this back to Context and the EF resolve what is update and what is created?
Like this?
using (var db = new CompanyContext())
{
db.Companies.Attach(cia);
db.Entry(cia).State = EntityState.Modified;
db.SaveChanges();
}
Thanks in advance.
In contrast to NHibernate, EF must be told what to update/create/delete explicitly in disconnected mode, as far as know. The good news is that there's a solution:
http://blog.brentmckendrick.com/introducing-graphdiff-for-entity-framework-code-first-allowing-automated-updates-of-a-graph-of-detached-entities/
I used it in one of my projects, worked a treat for me.
In EF cross reference tables are abstracted away by creating many-to-many relationships. E.G.
There's a SQL table dbo.TrialContactCrossReference that relates TrialContactId to TrialID. Now, EF did not generate an Entity TrialContactCrossReference because it went with this MANY-MANY relationship thing. How do I add a new row to said table?
I tried
context.TrialContacts.??? and context.ClinicalTrials.??? and just don't know what to do with this. If I have a new Contact that I want to relate to a trial how am I supposed to go about it?
trial.Contacts.Add(contact);
OR
contact.Trials.Add(trial);
OR (and my advise)
you could create an additional entity for cross reference table. this will convert many-many to 2 one-many relationships. more then %90 cases crosstables has additional columns (at least IsActive, RecordDate etc.) even it doesnt, it may be so in future and it requires you make lots of changes in code.
If I have a new Contact that I want to relate to a trial how am I supposed to go about it?
Assuming you have an existing Contact instance just do:
trial.TrialContacts.Add(contact);
context.SaveChanges();
EF will take care of the intermediate table insert for you. Note that adding Contacts and Trials works the same as if they weren't related.
There's a trick that was not obvious to me when setting this up. TableA must be added to TableB, not just to itself. In fact, looking at the generated entities each entity has a List<> of the other entity.
class TableA
{
List<TableB> TableB;
}
class TableB
{
List<TableA> TableA;
}
For example, if I want to add a TrialContact to a ClinicalTrial then I write:
context.ClinicalTrials.TrialContacts.Add(trialContact);
context.SaveChanges()
Then the xRef table be updated to reflect the relationship.
I have a model similar to this:
Context: The idea is that it's a database of samples. One sample has details, and several samples can be collated together into a CollatedSample, and the details can be collated together as well in a CollatedDetail. So, one CollatedSample has many CollatedDetails, and starts from many Samples, each of which has many Details. A CollatedDetail has many Details too. It's a "nice" square.
My approach to adding records is thus:
var sample = new Sample();
var detail = new Detail();
sample.Details.Add(detail);
// suppose I add a bit more meat to these entities...
var collatedSample = new CollatedSample();
var collatedDetail = new CollatedDetail();
collatedSample.Samples.Add(sample);
collatedSample.CollatedDetails.Add(collatedDetail);
collatedDetail.Details.Add(detail);
context.CollatedSamples.AddObject(collatedSample);
context.SaveChanges();
So I've added all elements to eachother, and added Detail to both Sample and CollatedDetail. On SaveChanges, I get an Update Exception with the jolly message:
Unable to determine the principal end of the 'SamplingModel.FK_Detail_CollatedDetailId' relationship. Multiple added entities may have the same primary key.
What I think might really be happening is there is an attempt to record the Detail entity before the CollatedDetail is recorded. That Detail table, with its two relationships, is the one causing the trouble (not adding them to either Sample nor CollatedDetail confirms it). Perhaps there is a way to specify the order of insertion? I also tried the reverse, to set the parent instead of using .Add() on children collections, with the same result. Otherwise, how do I make this sort of 2-pronged insertion in one shot?
EDIT: tl;dr:
I found a workaround: I removed the Foreign Key between Detail and CollatedDetail like #JaderDiag suggested, and the reference field from the CollatedDetail table. Entity Framework creates partial classes, so it was easy to create other partial classes for both entities and manually join them. This will be much much slower, I suspect, but it provides the same fluidity in later exploitation as the entities would have provided with the foreign key.
This is a workaround, and definitely not the solution I was looking for. Would vote this down if I could.