I have the following entities:
public class ModuleCriteria
{
public int ModuleCriteriaId { get; set; }
public string Criteria { get; set; }
public List<ModuleCriteriaLookup> ModuleCriteriaLookups { get; set;
}
}
public class ModuleCriteriaLookup
{
public int ModuleCriteriaLookupId { get; set; }
public int ModuleCriteriaId { get; set; } // ** (Foreign Key) **
public int SiteId { get; set; }
public string CategoryId { get; set; }
public ModuleCriteria ModuleCriteria { get; set; }
}
I have the following EF configuration in my Context
class (edited for brevity):
protected override void OnModelCreating( DbModelBuilder modelBuilder )
{
base.OnModelCreating( modelBuilder );
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<ModuleCriteriaLookup>().HasRequired( mc => mc.ModuleCriteria );
// I tried adding the below line but it made no difference.
//modelBuilder.Entity<ModuleCriteria>().HasMany( mc => mc.ModuleCriteriaLookups );
}
...and I have the following DbSet
properties defined in my Context
class:
public DbSet<ModuleCriteria> ModuleCriteria { get; set; }
public DbSet<ModuleCriteriaLookup> ModuleCriteriaLookup { get; set; }
I have a CriteriaRepository
class, which has a Save
method, for persisting changes for my ModuleCriteria
entities:
public void Save( ModuleCriteria moduleCriteria )
{
using ( var ctx = new MyAppContext() )
{
ctx.Entry( moduleCriteria ).State = moduleCriteria.ModuleCriteriaId == 0 ? EntityState.Added : EntityState.Modified;
ctx.SaveChanges();
}
}
A ModuleCriteria
object can exist without a ModuleCriteriaLookup
object, but ModuleCriteriaLookup
object has to relate to an existing ModuleCriteria
object (related on ModuleCriteriaId
).
You can have multiple ModuleCriteraLookup
objects all relating to the same one ModuleCriteria
object.
The behaviour that I would like, and expect with EF, is:
1) If I create a new ModuleCriteria
object (without any ModuleCriteriaLookups
), call the Save
method in my repository, I would expect to see new ModuleCriteria
record in the db with no related ModuleCriteriaLookup
records in the db.
2) If I create a new ModuleCriteria
object and assign a List<ModuleCriteriaLookup>
to it, call the Save method in my repository, I would expect to see new ModuleCriteria
record in the db and x new ModuleCriteriaLookup
rows in the db which relate to that particular ModuleCriteria
.
3) If I add/edit/remove any of the ModuleCriteriaLookup
objects that related to one of my ModuleCriteria
objects, then call the Save
method in my repository, I would expect to see any of the ModuleCriteria
's deleted ModuleCriteriaLookup
objects to get removed from the db, any new ones added and any edited ones simply to get updated.
So all I ever need worry about is that whatever the ModuleCriteria.ModuleCriteriaLookups
property contains for a given ModuleCriteria
, that's what will be reflected in the 2 tables in my DB by simply calling the Save method for the ModuleCriteria
object in my repository.
Unfortunately at the moment, if I'm adding a new ModuleCriteria
object with associated List<ModuleCriteriaLookup>
it adds both ModuleCriteria
and x ModuleCriteriaLookup
rows in the db nicely. But when I want to edit or delete entries in the ModuleCriteria.ModuleCriteriaLookups
property, this is not being reflected in the db. Nothing is happening with the ModuleCriteriaLookups
rows.
I'm not sure where exactly the problem is, whether its whether the EF mapping configuration, or something to do with how the repository works?
The problem is located in the repository. The DbContext
needs to be aware of the existence of entities. So when editing and/or deleting entities the entities need to be fetched from the database first.
This description clearly states:
The
.Entry
property returns objects from the context that are being tracked by the context.
Because you directly use this properties right after creating the context, the context isn't tracking these entities and is therefore not aware that something has changed. And thereby is unable to generate the correct SQL statements.
There are several ways to deal with this, depending on the rest of your design.
One way to delete it would be:
public void DeleteModuleCriteriaLookup(ModuleCriteriaLookup[] lookups)
{
using (var ctx = new MyAppContext())
{
var moduleCriteriaId = lookups.First().ModuleCriteriaId;
var moduleCritria = (
from criteria in ctx.ModuleCriteria
where criteria.ModuleCriteriaId == moduleCriteriaId
select criteria
).Single();
var lookupIdsToDelete = lookups.Select(l => l.ModuleCriteriaLookupId);
var lookupsToDelete = (
from lookup in moduleCritria.ModuleCriteriaLookups
where lookupIdsToDelete.Contains(lookup.ModuleCriteriaLookupId)
select lookup
).ToArray();
foreach (var lookup in lookupsToDelete)
{
moduleCritria.ModuleCriteriaLookups.Remove(lookup);
}
ctx.SaveChanges();
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.