System.NullReferenceException throw when build HasForeignKey [closed] - c#

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I have code c# like this
builder.Entity<EnPpTime>()
.HasOne(a => a.EnPpTimeInMeta).WithOne(b => b.EnPpTime)
.HasForeignKey<EnPpTimeInMeta>(e => e.Id);
when run the programe throw exception
System.NullReferenceException: Object reference not set to an instance of an object.
[2021-11-11T07:06:30.667Z] at Microsoft.EntityFrameworkCore.Metadata.Conventions.ForeignKeyAttributeConvention.UpdateRelationshipBuilder(IConventionForeignKeyBuilder relationshipBuilder, IConventionContext context)
[2021-11-11T07:06:30.668Z] at Microsoft.EntityFrameworkCore.Metadata.Conventions.ForeignKeyAttributeConvention.ProcessForeignKeyAdded(IConventionForeignKeyBuilder relationshipBuilder, IConventionContext`1 context)
[2021-11-11T07:06:30.668Z] at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnForeignKeyAdded(IConventionForeignKeyBuilder relationshipBuilder)
[2021-11-11T07:06:30.669Z] at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnForeignKeyAddedNode.Run(ConventionDispatcher dispatcher)
[2021-11-11T07:06:30.669Z] at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.DelayedConventionScope.Run(ConventionDispatcher dispatcher)
[2021-11-11T07:06:30.670Z] at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ConventionBatch.Run()
[2021-11-11T07:06:30.670Z] at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ConventionBatch.Run(IConventionForeignKey foreignKey)
[2021-11-11T07:06:30.671Z] at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionBatchExtensions.Run(IConventionBatch batch, InternalForeignKeyBuilder relationshipBuilder)
[2021-11-11T07:06:30.671Z] at Microsoft.EntityFrameworkCore.Metadata.Builders.ReferenceReferenceBuilder.HasForeignKeyBuilder(EntityType dependentEntityType, String dependentEntityTypeName, Func`3 hasForeignKey)
[2021-11-11T07:06:30.672Z] at Microsoft.EntityFrameworkCore.Metadata.Builders.ReferenceReferenceBuilder.HasForeignKeyBuilder(EntityType dependentEntityType, String dependentEntityTypeName, IReadOnlyList`1 foreignKeyMembers)
[2021-11-11T07:06:30.672Z] at Microsoft.EntityFrameworkCore.Metadata.Builders.ReferenceReferenceBuilder`2.HasForeignKey[TDependentEntity](Expression`1 foreignKeyExpression)
How to fix this exception

Looks like You're missing the
.HasPrincipalKey
in this case it will default to look for entityname suffixed "ID" in Your case "EnPpTimeID" which if it doesn't exist will fail
It is a very good idea when using entity framework always to use EntityTypeNameID for identity column in this case you will not have to explicitly defined the foreign and principal key

This appears to be a known bug when there are multiple one-to-one relationships between two entity types.
Calling entity.HasOne(d => d.Parent).WithOne(p => p.Child) before entity.HasKey() solved the problem for me. Read on for details:
I had the same problem using EF core 5 - .HasForeignKey() throws the said exception.
The DbContext was scaffolded. Scaffoling does not generate .HasPrincipalKey() for single-column foreign keys. Manually adding .HasPrincipalKey() did not fix the problem. My tables however had two 1:1 relationships. This means that the child table has 4 constraints: two foreign keys and two unique keys on the same columns as the FKs. The scaffolded code is:
builder.Entity<Child>(entity =>
{
// 2 unique keys.
entity.HasKey(e => e.ParentId);
entity.HasIndex(e => new { e.OtherId, e.ParentId }).IsUnique();
entity.Property(e => e.ParentId).ValueGeneratedNever();
// 2 foreign keys.
entity.HasOne(d => d.Parent).WithOne(p => p.Child)
.HasForeignKey<Child>(d => d.ParentId); // <---- Throws exception!
entity.HasOne(d => d.Parent2).WithOne(p => p.Child2)
.HasPrincipalKey<Parent>(p => new { p.OtherId, p.Id })
.HasForeignKey<Child>(d => new { d.OtherId, d.ParentId });
});
When I moved entity.HasOne(d => d.Parent).WithOne(p => p.Child)... before entity.HasKey() the problem disappeared. However, you should not modify generated code. I inherited the scaffolded DbContext and in the subclass wrote this:
protected override void OnModelCreating(ModelBuilder builder)
{
// Bugfix:
builder.Entity<Child>().HasOne(d => d.Parent).WithOne(p => p.Child);
// You don't even need .HasForeignKey() here. It will be called inside base.OnModelCreating(). Duplicating .HasOne() and .WithOne() works fine.
base.OnModelCreating(builder);
}

Related

How can i configure model builder to delete all recipes when user is deleted but when recipe is deleted keep the user [duplicate]

This question already has an answer here:
Cascade deleting with EF Core
(1 answer)
Closed 2 years ago.
This is my model builder right now, but when i delete user it sets recipes userid to null.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ApplicationUser>().HasMany(e => e.Recipes).WithOne(e => e.ApplicationUser)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Recipe>().HasOne(e => e.ApplicationUser).WithMany(e=>e.Recipes)
}
I think you've overstated the mapping, you only need to map one entity to the other.
Try to use this one first;
modelBuilder.Entity<ApplicationUser>().HasMany(e => e.Recipes).OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Recipe>().HasOne(e => e.ApplicationUser);
If the above doesn't work, try this one alone;
modelBuilder.Entity<ApplicationUser>().HasMany(e => e.Recipes).OnDelete(DeleteBehavior.Cascade);

EF Core - 2 Entities, each with a reference to another lookup Entity. On Add - IOE - cannot be tracked because another instance with the key value

We're using EF Core 3.1
We have 2 Entities - item and batch. Each have a reference to currency. When we add both an item and a batch, each with a reference to a loaded (and tracked) currency EF Core spits out the following System.InvalidOperationException:
The instance of entity type 'Currency' cannot be tracked because another instance with the key value '{Id: 103}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.
We're not doing anything too irregular:
var currency = _context.Set<Currency>.SingleOrDefault(currencyId);
var item = new Item(currency);
var batch = Batch.Create(currency, new[] { item });
_context.Set<Batch>.Add(batch);
item.Batch = batch;
_context.Set<Item>.Add(instruction);
And our maps have fks etc ItemMap:
modelBuilder
.HasOne(i => i.Currency)
.WithMany()
.IsRequired();
modelBuilder
.HasOne(i => i.Batch)
.WithMany();
and BatchMap:
modelBuilder
.HasOne(i => i.Currency)
.WithMany()
.IsRequired();
and CurrencyMap:
modelBuilder
.ToTable("Currency")
.HasKey(cur => cur.Id);
modelBuilder
.HasData(new Currency(103));
I wonder if anyone can point out my stupidity or at least explain where I may be going wrong?

NHibernate ClassMapping creates automatic a unique key

I use NHibernate with ClassMapping. I created an index on one of the properties, like this:
public class ShopMapping : ClassMapping<Shop>
{
public ShopMapping()
{
Table("Shops");
Id(p => p.Id, m => m.Generator(NHibernate.Mapping.ByCode.Generators.GuidComb));
Property(p => p.CountryCode, m =>
{
m.Length(10);
m.NotNullable(true);
m.Index("ShopCountryCodeIdx");
m.Unique(false);
});
}
}
This generates the index called ShopCountryCodeIdx, but I got also a unique index, called 'CountryCode' on the same column. I tried it with an without m.Unique(false), but no effects.
I just moved to a new pc. Old pc: VS2012 on 32bitand new pc: VS2015 on 64bit. NHiberate version is on both the same (3.4.1.4). Database is MySQL 5.7 (on old machine I used MySQL 5.5).
How is this possible?
Part of the problem found. I had in one of my other ClassMapping classes an unique index across three columns. One of the was also a CountryCode column. That results in this strange behavior.
Property(p => p.CountryCode, m =>
{
m.Length(10);
m.NotNullable(true);
m.Index("PanelShopCountryCodeIdx");
//m.UniqueKey("UK_psPanelShopnrIdx");
});
Property(p => p.ShopNr, m =>
{
m.Length(25);
m.NotNullable(true);
//m.UniqueKey("UK_psPanelShopnrIdx");
});
Property(p => p.PanelCode, m =>
{
m.Length(25);
m.NotNullable(true);
// m.UniqueKey("UK_psPanelShopnrIdx");
});
Getting rid of those m.UniqueKey statements, solved the problem (which let me with another challenge, how to create in this scenario a unique index across three columns from which one column has also an own (non unique) index...

NHibernate map by code keycolumn?

just started on a project to convert a NHibernate Fluent mapping into the NHibernate Mapping By Code as part of an upgrade associated with one of my old applications.
Almost there, but I stumbled upon something I can't convert properly and found myself stumped. Now I hope maybe some of you experienced out there can help me with it.
Below is the original mapping using Fluent:
HasMany<ExampleEntity>(x => x.OtherExampleEntities)
.OptimisticLock.False()
.AsSet()
.KeyColumn("ParentExampleEntityId")
.Inverse()
.Cascade.SaveUpdate();
Now I got stuck on converting the KeyColumn-part of my mapping, below is my current progress (thus keyColumn still being there):
Set(x => x.OtherExampleEntities, x => {
x.OptimisticLock(false);
x.KeyColumn("ParentExampleEntityId");
x.Inverse(true);
x.Cascade(Cascade.Persist);
}, map => map.OneToMany(r => r.Class(typeof(ExampleEntity))));
There's not a lot of documentation regarding the mapping by code part of NHibernate but I've been spending a lot of time with the posts made by notherdev (#blogspot.se). All help is appreciated.
There is a comprehensive post about <set> mapping
Mapping-by-Code - Set and Bag by Adam Bar
Small snippet, but please observe the post:
Set(x => x.Users, c =>
{
c.Fetch(CollectionFetchMode.Join); // or CollectionFetchMode.Select,
// CollectionFetchMode.Subselect
c.BatchSize(100);
c.Lazy(CollectionLazy.Lazy); // or CollectionLazy.NoLazy, CollectionLazy.Extra
c.Table("tableName");
c.Schema("schemaName");
c.Catalog("catalogName");
c.Cascade(Cascade.All);
c.Inverse(true);
c.Where("SQL command");
c.Filter("filterName", f => f.Condition("condition"));
c.OrderBy(x => x.Name); // or SQL expression
c.Access(Accessor.Field);
c.Sort<CustomComparer>();
c.Type<CustomType>();
c.Persister<CustomPersister>();
c.OptimisticLock(true);
c.Mutable(true);
<key column="" ...> mapping:
c.Key(k =>
{
k.Column("columnName");
// or...
k.Column(x =>
{
x.Name("columnName");
// etc.
});
k.ForeignKey("collection_fk");
k.NotNullable(true);
k.OnDelete(OnDeleteAction.NoAction); // or OnDeleteAction.Cascade
k.PropertyRef(x => x.Name);
k.Unique(true);
k.Update(true);
});
....

Foreign Key to a table with 2 columns primary key (CompositeId)

I've defined the primary key as following:
CompositeId()
.KeyProperty(x => x.Id)
.KeyProperty(x => x.Type);
I've tried the following:
References(x => x.EntityWith2ColsPK);
And failed with:
Foreign key (Fk_MyEntity_EntityWith2ColsPK:MyEntities [Fk_EntityWith2ColsPK])) must have same number of columns as the referenced primary key (EntityWith2ColsPKs [Id, Type])
How can I reference EntityWith2ColsPK from another entity?
Update:
I've tried the following (according to AlfeG's comment):
HasMany<EntityWith2ColsPK>(x => x.EntityWith2ColsPK).KeyColumns.Add("Id", "Type").Cascade.All();
Which failed with:
Custom type does not implement UserCollectionType: EntityWith2ColsPK
But anyway I don't want a 1 to many relation, I want a 1 to 1 relation. Still, I can't make either of them work.
Also, I've tried:
HasOne<EntityWith2ColsPK>(x => x.EntityWith2ColsPK).PropertyRef(x => x.Id).PropertyRef(x => x.Type);
Which fails with:
NHibernate.MappingException : property not found: Type on entity EntityWith2ColsPK
What can I do for this to really work?
I managed to achieve something in the db.. but yet, for some reason I suspect it maps the property "Type" twice, because I want it to be both part of the Primary Key, and part of the Foreign Key..
This is what I did:
References(x => x.EntityWith2ColsPK).Columns("EntityWith2ColsPKId", "Type").Formula("Id = :EntityWith2ColsPKId AND Type = :Type");
But I received the following exception:
System.IndexOutOfRangeException : Invalid index 8 for this SqlParameterCollection with Count=8.
Because the mapping of this entity is same as EntityWith2ColsPK:
CompositeId()
.KeyProperty(x => x.Id)
.KeyProperty(x => ((ILocalizedEntity) x).Language);
HELP!
You can use something like this since you aren't using cascade anyway on your Reference
References(x => x.EntityWith2ColsPK)
.Columns(new string[] { "ID", "TYPE" })
.Not.Update()
.Not.Insert();

Categories

Resources