EF "The member with identity X does not exist in the metadata collection" (and NopCommerce) - entity-framework

First of all and as you can see in the title, I'm designing a plugin for nopCommerce. I believe that the problem is not related to it (but with Entity Framework) but I'm not really sure.
My plugin has access to data, and nopCommerce let's me create my own context, creating the required tables and relations.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ParentMap());
modelBuilder.Configurations.Add(new ChildMap());
}
Conceptually, what I would like to have is:
ROOT TABLE ----(1:N)---- CHILDTABLE ----(1:1)---- EXISTING NOPCOMMERCE TABLE
And the tables and columns created in the DB seems correct to me. The mappings are pretty simple:
public ParentMap()
{
ToTable("TableA");
HasKey(m => m.Id);
Property(m => m.SomeProperty);
HasMany(m => m.Child).WithRequired(s => s.Parent).WillCascadeOnDelete();
}
public ChildMap()
{
ToTable("TableB");
HasKey(m => new { m.Id });
HasRequired(m => m.NopCommerceEntity);
HasRequired(m => m.Parent);
}
Till this point, everything seems to work pretty well, things get registered and the application starts. When I try to insert or update anything that has relation with the nopCommerce entity, I get the following exception:
"The member with identity 'Namespace.ChildObject_NopCommerceEntity' does not exist in the metadata collection.\r\nParameter name: identity".
I've been thinking that the problem could be related with the fact that I'm not adding other mappings in my OnModelCreating. I've tried to add all the related mappings there but I get the same exception.
It's a bit complicated. I'd be very greatful for your help & time :)

You are right this issue related to Entity Framework because EF does not support cross-project POCO relations. You have to remove any property that has an entity from NopEntities in your plugin and instead use an Id of that entity as int as below :
public int ProductId { get; set; }
instead of
public virtual Product Product { get; set; }
and in the mapping you should not specify the relationship between your entity and the Nop.

I think you can still use the following relation in your child class
public int ProductId { get; set; }
public virtual Product Product { get; set; }
but when you save or update the child class, instead of setting
child.Product = product
instead set the following
child.ProductId = product.Id
and also i think in your PluginObjectContext plugin class inherits from NopObjectContext.

Related

"The association has been severed but the relationship is either marked as 'Required' or is implicitly required..."

I am getting the following error when trying to add a migration:
PS C:\Code\morpher.ru\Morpher.Database> dotnet ef migrations add AddQazaqFeatures --startup-project=../Morpher.Database.Design
Build started...
Build succeeded.
System.InvalidOperationException: The association between entity types 'Service' and 'Deployment' has been severed but the relationship is either m
arked as 'Required' or is implicitly required because the foreign key is not nullable. If the dependent/child entity should be deleted when a requi
red relationship is severed, then setup the relationship to use cascade deletes. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLoggin
g' to see the key values.
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.HandleConceptualNulls(Boolean sensitiveLoggingEnabled, Boolean forc
e, Boolean isCascadeDelete)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.CascadeDelete(InternalEntityEntry entry, Boolean force, IEnumerable`1 fore
ignKeys)
...
My code:
public class Deployment
{
public int Id { get; set; }
public virtual Service Service { get; set; }
public int ServiceId { get; set; }
public string Host { get; set; }
public short? Port { get; set; }
public string BasePath { get; set; }
}
public class Service
{
public int Id { get; set; }
public string Name { get; set; }
public string UrlSlug { get; set; }
public virtual ICollection<Endpoint> Endpoints { get; set; }
public virtual ICollection<Deployment> Deployments { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Service>().HasData(new Service
{
Name = "Веб-сервис «Морфер»",
UrlSlug = "ws",
Id = 1
});
modelBuilder.Entity<Deployment>().HasData(new Deployment
{
Host = "ws3.morpher.ru",
ServiceId = 1,
Id = 1
});
modelBuilder.Entity<Deployment>(entity =>
{
entity.Property(e => e.Host).IsRequired().HasMaxLength(256);
entity.Property(e => e.BasePath).HasMaxLength(512);
entity.HasOne(deployment => deployment.Service)
.WithMany(service => service.Deployments)
.HasForeignKey(d => d.ServiceId)
.OnDelete(DeleteBehavior.Restrict)
.HasConstraintName("FK_Deployments_Services");
});
}
There are numerous StackOverflow questions mentioning the same error (1, 2, 3), but they are mostly to do with removing entities while not having a CASCADE delete policy or a nullable foreign key.
In my case, I am trying to add new rows and I don't see why it is considering the relationship 'severed'. Is setting ServiceId = 1 not enough?
I was able to reproduce the issue in latest at this time EF Core 3.1 version (3.1.28) by first removing the model data seeding code (HasData calls), then adding migration for just creating the tables/relationships, then adding the data seeding code and attempting to add new migration.
It does not happen in latest EF Core 6.0, so apparently you are hitting EF Core 3.1 defect/bug which has been fixed somewhere down on the road. So you either need to upgrade to a newer EF Core version (with all associated burdens like retesting everything, breaking changes etc.), or use the workaround below.
The workaround is to replace the DeleteBehavior.Restrict with either ClientNoAction or NoAction. Values of that enum and documentation of what they do is kind of messy, but all these 3 values seem to generate one and the same regular enforced FK constraint (with no cascade) in the database, and differ only by client side behavior, or in other words, what does EF Core change tracker do with related tracked entities when "deleting" a principal entity. And in this particular case, `Restrict" throws exception when there are tracked (loaded) related entity instances, while the other two won't.
I know you think you are just "adding data", but EF Core model data seeding is more than that - it tries to keep that data, so in some circumstances it needs to update or delete previously added data. Which in general works, except when there are bugs in the EF Core codebase, like in this case.

How can I implement a 1..n bi-directional relationship in Entity Framework Code First

I am absolutely stumped in trying to figure out how to implement a bi-directional 1..n relationship in Entity Framework using Code First. For example, a team (represented by a Team entity) has a coach and a manager (both represented by a Person entity). So, my Team model could be as follows:
public class Team
{
public Team()
{
Manager = new Person();
Coach = new Person();
}
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int TeamID { get; set; }
public string Name { get; set; }
[ForeignKey("Manager")]
public int ManagerID { get; set; }
public virtual Person Manager { get; set; }
[ForeignKey("Coach")]
public int CoachID { get; set; }
public virtual Person Coach { get; set; }
}
I can implement one-way navigation by implementing the Person Entity as follows:
public class Person
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int PersonID { get; set; }
public string Name { get; set; }
}
and the fluent API:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Team>()
.HasRequired(t => t.Manager);
modelBuilder.Entity<Team>()
.HasRequired(t => t.Coach);
base.OnModelCreating(modelBuilder);
}
However, while that allows me to navigate from the Team entity to the related Coach and Manager (both instances of Person), it doesn't allow me to directly navigate from the Coach or Manager to the related Team. So, to implement 2-way navigation, I modified the Person entity as follows:
public class Person
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int PersonID { get; set; }
public string Name { get; set; }
[ForeignKey("Team")]
public int TeamID { get; set; }
public virtual Team Team { get; set; }
}
While that builds ok, I get the following runtime error when I try to save to the database:
System.Data.Entity.Core.UpdateException
InnerException: Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements, or store-generated values.
So, to specify the ordering between the entities, I tried to modify the fluent API by adding the "WithRequiredPricipal" as follows:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Team>()
.HasRequired(t => t.Manager)
.WithRequiredPrincipal(t => t.Team);
modelBuilder.Entity<Team>()
.HasRequired(t => t.Coach)
.WithRequiredPrincipal(t => t.Team);
base.OnModelCreating(modelBuilder);
}
However, when I attempt to execute "add-migration" in the Package Manager Console, I get the following error:
System.InvalidOperationException: The navigation property 'Team' declared on type 'RelatedEntities.Models.Person' has been configured with conflicting foreign keys.
What I'm attempting to achieve seems like a straightforward requirement but I've done heaps of searching for a solution without yet finding an answer. Am I missing something in the fluent API or the annotations?
(I don't want to implement a workaround, such as implementing separate models for Coach and Manager because a team may have numerous other roles (eg, Assistant Coach, Public Relations Manager, etc). I would want each to simply be an instance of a Person entity.)
You didn't define your foreign key constraints.
.HasRequired(t => t.Manager)
.WithMany()
.HasForeignKey(t => t.ManagerId)
As a side note. If your manager was managing multiple teams the WithMany would be .WithMany(m => m.Teams) and your manager model would need something like this:
private ICollection<Team> _teams
public ICollection<Team> Teams
{
get { return _teams ?? (teams = new List<Team>()); }
protected set { _teams = value; }
}
Sorry for formatting. On my phone. Good luck.
Ok, I can now answer my own question in case anyone else encounters the same problem.
Firstly, as I mention in my comment above, the problem that I described in my question turns out to be a recognized shortcoming in Entity Framework that the EF Triage Team has flagged to be addressed in a future release of EF.
In the meantime, the workaround that has been suggested by a number of contributors in response to questions about how to implement circular dependencies in EF (which is what my example above is trying to do) is to do it in stages as follows:
Create the principal entity
Call SaveChanges() on DbContext
Create the dependent entity and set the foreign key before calling SaveChanges() again (at some subsequent point)
So, using the Team example in my original question above, instead of creating the dependent Manager and Coach entities in the Team constructor, the first change was to make the Team's foreign keys to the Coach and Manager optional (instead of required), so that the Team could be instantiated without the Coach and Manager, and then call SaveChanges():
Team team = Teams.Add(new Team());
SaveChanges();
After that, I then create the dependent Manager and Coach entities and set their foreign keys to the ID of the Team instance:
team.Manager = new Person();
team.Manager.TeamID = team.TeamID;
team.Coach = new Person();
team.Coach.TeamID = team.TeamID;
At any time after that, SaveChanges() can be called without causing a runtime error as previously.
When this issue is addressed in a future release of EF, it should be possible to create the principal and dependent entities without having to call SaveChanges() in between.

How do you get a web API odatamodelbuilder to work with EF fluent API mappings

I have created a fairly simply domain model using pocos. I have mapped these to an EF DB context using EntityTypeConfiguration<TEnitityType> classes. This all works fine.
I am now trying to create an OData V4 WebAPI controller endpoint using a ODataConventionModelBuilder and this is where things are coming unstuck. It all works fine until it encounters an association that is not convention based. But I cannot find a way to get the ODataBuilder to pick up the mappings from my EntityTypeConfiguration<TEnitityType> classes.
This leaves my with 2 unpalatable options
Decorate my lovely clean pocos with dirty attributes.
Re-map all the non convention based mappings manually using the ODataBuilder
Not sure if code samples will help but here they are anyway, i have simplified the entities for brevity.
var builder = new ODataConventionModelBuilder();
builder.EntitySet<Item>("Items");
config.MapODataServiceRoute(
routeName: "odata",
routePrefix: "odata",
model: builder.GetEdmModel(),
batchHandler: new DefaultODataBatchHandler((GlobalConfiguration.DefaultServer)));
public class Item
{
public Int32 Id { get; set; }
public Int16 ItemTypeId { get; set; }
public virtual ItemType Type { get; set; }
public virtual ICollection<ItemVersion> Versions { get; set; }
public virtual ICollection<ItemTag> Tags { get; set; }
}
The problem comes when it encounters the ItemTags collection, here is an ItemTag:
public class ItemTag
{
public Int32 ItemId { get; set; }
public string Tag { get; set; }
public Item Item { get; set; }
}
Which you can see is not convention based and I have a configuration class for it as follows:
public class ItemTagConfiguration : EntityTypeConfiguration<ItemTag>
{
public ItemTagConfiguration()
{
HasKey(x => new {x.ItemId, x.Tag});
HasRequired(x => x.Item)
.WithMany(y => y.Tags)
.HasForeignKey(x => x.ItemId);
}
}
Does anyone know of a way that I can use these EntityTypeConfiguration files with an ODataBuilder or web API?
EDIT
If found this page which seems to indicate it might be possible with EF 6 which I am using. What I want to do is this
ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Dbf>("Dbfs");
// modelBuilder.Configurations.Add(new DbfMap()); <---- NO GOOD - Needs Class from DBContext we only have a model builder :(
Microsoft.Data.Edm.IEdmModel model = modelBuilder.GetEdmModel();
config.Routes.MapODataRoute("ODataRoute", "odata", model);
but the builder does not have a Configurations property.
Two things:
I have read multiple sources now that ward against using lazy loading and serialization; which is basically what OData is; (It even uses the system.runtime.serialization.datacontract and datamember attributes)
I have had more success in explicitly loading from context, and defining navigation properties in the modelbuilder for dbContext. I understand you are looking at customized nav properties, but I am fairly sure these are overriden methods useful for the ODataModelBuilder class (that does not assume much and needs less Entity Framework to work). Where you mentioned using EF already, I imagine that is the direction you will work, and if you do not need to alias your model names, you add an entry for each Set, using convention naming.
EntitySet("routePrefixName")
in building the EdmModel, and it wires up the relationships you made using Fluent previously. If you do have to add extraneous items to the underlying model, you should define each class as an EntityType<>(), only setting the key. EdmBuilder can use mild properties and key association to attach to the EF model in the ODataConventionModelBuilder.
I have wrestled and sought for some time, and there does not seem to be a wealth of information on .Net OData v4 floating around, probably due to the whole force datetimeoffset issue.
Hope that helps somewhat

Entity Framework Code First One-to-One Required-Required Relationship

When using Entity Framework Code First 4.3.1 it is possible to create relationships with a multiplicity of 1-to-1. That is, one entity on each end of the relationship.
It is possible to configure 1-to-1 relationships to be required-required or required-optional ^. However, when I switch between the two I do not see any differences in:
The database schema generated. I am targeting SQL Server 2008.
The runtime behaviour of EF.
As such, I am able to create a RequiredPrincipalAs record without a corresponding RequiredDependentAs record, despite the relationship being configured as required-required. This seems to contradict the documentation for HasRequired(...):
Configures a required relationship from this entity type. Instances of the entity type will not be able to be saved to the database unless this relationship is specified. The foreign key in the database will be non-nullable.
http://msdn.microsoft.com/en-us/library/gg671317
The required-required relationship entities:
public class RequiredPrincipalA
{
public int Id { get; set; }
public virtual RequiredDependentA DependentA { get; set; }
}
public class RequiredDependentA
{
public int Id { get; set; }
public virtual RequiredPrincipalA PrincipalA { get; set; }
}
The required-optional relationship entities:
public class RequiredPrincipalB
{
public int Id { get; set; }
public virtual OptionalDependentB DependentB { get; set; }
}
public class OptionalDependentB
{
public int Id { get; set; }
public virtual RequiredPrincipalB PrincipalB { get; set; }
}
The DbContext and model configuration:
public class AppContext : DbContext
{
public DbSet<RequiredPrincipalA> PrincipalAs { get; set; }
public DbSet<RequiredDependentA> DependentAs { get; set; }
public DbSet<RequiredPrincipalB> PrincipalBs { get; set; }
public DbSet<OptionalDependentB> DependentBs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<RequiredPrincipalA>()
.HasRequired(o => o.DependentA)
.WithRequiredPrincipal(o => o.PrincipalA);
modelBuilder.Entity<RequiredPrincipalB>()
.HasOptional(o => o.DependentB)
.WithRequired(o => o.PrincipalB);
}
}
The test code:
Database.SetInitializer(new DropCreateDatabaseAlways<AppContext>());
using (var ctx = new AppContext())
{
ctx.Database.Initialize(force: false);
ctx.PrincipalAs.Add(new RequiredPrincipalA());
ctx.PrincipalBs.Add(new RequiredPrincipalB());
ctx.SaveChanges();
}
I am aware I could add a [Required] data attribute to the navigation properties of RequiredPrincipalA.DependentA and RequiredDependentA.PrincipalA. This would cause EF validation to prevent the scenario above. However, I do not want to do this because it also validates the navigation property is populated when updating an existing entity. This means the application has to pre-fetch the entity at the other end of the relationship for every update.
Why do I not see any difference in the behaviour of EF just when changing a relationship between required-required and required-optional?
^ Note that optional-optional is also supported but this doesn't form part of my question. There are obvious differences in the generated database schema and runtime behaviour when an optional-optional relationship is configured.
I don't know why required-required is allowed for this case but it cannot exist in the database because relation is build on primary keys. Required-required means that A cannot be inserted if related B doesn't exist and B cannot be inserted if related A doesn't exist => neither A or B can be inserted.
Database relation has always principal and dependent entity - principal can always exist without dependent.
Real required-required in EF can be achieved only when both A and B are mapped to the same table (table splitting) because in such case they are both inserted with single insert command.
Not really an answer but I have more to say than will fit in comments. But you know, I write 900 page books...it's just how I roll. :)
Oddly I would expect the fluent configuration to behave the same way as the data annotation and am confused that it's not doing it. (I've pinged Rowan Miller with a link to this thread to get his feedback.) And the behavior I mean is: validating the constraint during SaveChanges.
On the database side, I'm with Ladislav.In the model, EF defines the 1:1 using the keys of the related entities. But in the database, you can't have FKs in both tables, so only the dependent table in the database will require that constraint that it's PK maps to an existing PK in the principal table.
And finally, I understand your reason for not wanting EF to enforce the relationship if you aren't going to always deal with teh full graph. I think 1:1 relationships are the most confusing of the EF relationship mappings and I always find myself having to go back for reminders of the rules and how things should work.
Old question. But since EF6 is still used and even available for .Net standard and this issue can be a real nuisance, I think it's worth mentioning something I couldn't find in other answers.
It is true that both HasRequired - WithRequiredPrincipal and HasOptional - WithRequired produce the same database schema and the same runtime behavior. That is, with both mappings it's possible to save a principal without a dependent entity and to remove the dependent later. So much for HasRequired.
But there is a way to make EF validate the required relationship when creating the entities, which is by simply adding a [Required] attribute:
public class RequiredPrincipalA
{
public int Id { get; set; }
[Required] // <== here
public virtual RequiredDependentA DependentA { get; set; }
}
public class RequiredDependentA
{
public int Id { get; set; }
public virtual RequiredPrincipalA PrincipalA { get; set; }
}
As said, only when creating the entities. It's still possible to set RequiredPrincipalA.RequiredDependentA = null and save it successfully. But I think that, fortunately, the likelihood of that happening in code is far lower than forgetting to set the required dependent.

Why do I get a "relationship multiplicity violation" accessing a relation property?

I have the following classes in which I am trying to map the entity object to the view model:
public class ConsumerIndexItem: MappedViewModel<Consumer>
{
public string UserName { get; set; }
public string RoleDescription { get; set; }
public override void MapFromEntity(Consumer entity)
{
base.MapFromEntity(entity);
UserName = entity.User.UserName;
}
}
public class Consumer: AuditableEntity
{
public virtual User User { get; set; }
public virtual Role Role { get; set; }
}
public class IndexModel<TIndexItem, TEntity> : ViewModel where TEntity : new()
{
public IndexModel()
{
Items = new List<TIndexItem>();
}
public List<TIndexItem> Items { get; set; }
public virtual void MapFromEntityList(IEnumerable<TEntity> entityList)
{
Items = Mapper.Map<IEnumerable<TEntity>, List<TIndexItem>>(entityList);
}
}
public class ConsumerIndexModel: IndexModel<ConsumerIndexItem, Consumer>
However, if I drive the mapping with the following code:
var model = new ConsumerIndexModel();
var list = _repository.List().Where(c => c.Parent == null).ToList();
model.MapFromEntityList(list);
return View(model);
on the line UserName = entity.User.UserName; in ConsumerIndexItem I get the following exception:
A relationship multiplicity constraint violation occurred: An EntityReference can have no more than one related object, but the query returned more than one related object. This is a non-recoverable error.
If I execute ?entity.User.UserName in the Immediate Window I get the expected user name value. What could be wrong here?
Let me explain why I had this exception and you may be able to correlate it with your own situation. I had EF Code First model mapped to the existing database. There was one-to-many relationship between two of the entities. The child table had composite primary consisting of the Id and Date. However, I missed the second segment of the primary key in my fluent map:
this.HasKey(t => t.Id);
The strange part of that was that the model worked but was throwing an exception in certain cases and it was very hard to understand why. Apparently when EF was loading the parent of child entity there were more than one parent since the key had not only Id but Date as well. The resolution was to include the second part of the key:
this.HasKey(t => new { t.Id, t.Date });
The tool that helped me to pinpoint the problem was EF Power Tools, currently it is in Beta 3. The tool gives a context menu for the EF context class where one the item is View Entity Model DDL SQL. Although I could have found this just by checking the code, the tool is nice in showing how close the EF model matches the actual database.
I believe that you're getting this exception because for a some reasons the multiplicity of relationship is violated. In my case it was incorrect mapping, in your it may be something else, I can't tell by looking at your code.
I think the problem maybe that you suppose that every user has only one consumer while this is not correct regarding data.
I had the same problem and it was because the relationship was on-to-many and I made it one-to-one.