NHibernate C# many-to-many with enum list - c#

I have this entity :
public class EntityA
{
public virtual required EntityB Name { get; set; }
public virtual IList<MyEnum>? ConnectedEnums { get; set; }
}
public void Override(AutoMapping<EntityA> mapping)
{
mapping
.HasManyToMany(x => x.ConnectedEnums)
.Table("EntityA_ConnectedEnums");
mapping.Map(x => x.Name). ...
mapping.Map(x => x.ConnectedEnums)
.CustomType<IList<MyEnum>>();
}
I would like to use a many-to-many table with MyEnum and EntityB. Name mapping is ok, but for ConnectedEnums says:
NHibernate.MappingException: An association from the table EntityA_ConnectedEnums refers to an unmapped class: Enums.MyEnum

Related

entities that do not expose foreign key properties for their relationships (EF) [duplicate]

This question already has answers here:
An error occurred while saving entities that do not expose foreign key properties for their relationships
(16 answers)
Closed 2 months ago.
When trying to call SaveChanges(), I get the following error:
An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for details.'
SqlException: Invalid column name 'Artwork_Id'
I am using Entity Framework.
I'm trying to add an artworkImage that has the Id of an artwork as a reference. All information is being passed correctly but it's not saving.
I've tried adding foreign keys to my models and dbcontext but I've not gotten further than the code below.
public partial class ArtworkImage
{
[Key]
public int Id { get; set; }
public string ImageURL { get; set; }
public Artwork Artwork { get; set; }
}
public partial class Artwork
{
[Key]
public int Id { get; set; }
public string Category { get; set; }
public ICollection<ArtworkImage> ArtworkImage { get; set; }
}
My DbContext:
public DbContext()
: base("name=DbConnection")
{
this.Configuration.AutoDetectChangesEnabled = false;
}
public virtual DbSet<Artwork> Artworks { get; set; }
public virtual DbSet<ArtworkImage> ArtworkImages { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Artwork>()
.Property(e => e.Category)
.IsFixedLength();
modelBuilder.Entity<Artwork>()
.HasKey(b => b.Id);
modelBuilder.Entity<ArtworkImage>()
.HasKey(b => b.Id);
Database.SetInitializer<DbContext>(null);
base.OnModelCreating(modelBuilder);
}
I believe I should be adding something like this to my dbcontext but I haven't quite figured it out yet.
modelBuilder.Entity<ArtworkImage>()
.HasRequired(p => p.Artwork)
.WithMany(d => d.ArtworkImage)
.HasForeignKey(p => p.Artwork);
If any information is missing please point it out and I'll add it.
You have to declare primary key on each table. it is a rare occasion when a table has no PK. almost never.
[Key]
public int Id { get; set; }
So part of your problem might be that you don't define the relationship in reverse which I believe is important in how it establishes if the relationship is one-to-one or one-to-many. So you will likely need to add a property on the Artwork class that is of type ArtworkImage (if it is one-to-one). if it is one-to-many you will need to make the property some generic collection with the generic of type ArtworkImage.
One-to-one
public partial class Artwork
{
[Key]
public int Id { get; set; }
public string Category { get; set; }
public ArtworkImage ArtworkImage { get; set; }
}
One-to-many
public partial class Artwork
{
[Key]
public int Id { get; set; }
public string Category { get; set; }
public IEnumerable<ArtworkImage> ArtworkImages { get; set; }
}

EntityFrameworkCore - Cannot use table 'AspNetUserRoles' for entity type DeltaIdentityUserRole since it is being used for entity type 'AspNetUserRoles

I am trying to set many-many relationship with AspNetUserRoles in .Net 6, EntityFrameworkCore
but getting error:
Cannot use table 'AspNetUserRoles' for entity type 'DeltaIdentityUserRole' since it is being used for entity type 'AspNetUserRoles (Dictionary<string, object>)' and potentially other entity types, but there is no linking relationship. Add a foreign key to 'DeltaIdentityUserRole' on the primary key properties and pointing to the primary key on another entity type mapped to 'AspNetUserRoles'.
Here is the code:
public class DeltaIdentityUser<T> : IdentityUser<int>
{
public virtual UserProfile User { get; set; }
}
public class DeltaIdentityRole<T> : IdentityRole<int>
{
internal virtual ICollection<UserProfile> UserProfiles { get; set; }
}
public class DeltaIdentityUserRole<T> : IdentityUserRole<int>
{
public virtual UserProfile User { get; set; }
}
DB Context:
DeltaContext : DeltaIdentityContext<DeltaIdentityUser<int>, DeltaIdentityRole<int>, int, IdentityUserClaim<int>, DeltaIdentityUserRole<int>, IdentityUserLogin<int>, IdentityRoleClaim<int>, IdentityUserToken<int>>
DBSet:
public virtual DbSet<DeltaIdentityUser<int>> AspNetUser { get; set; } = null!;
public virtual DbSet<DeltaIdentityUserRole<int>> AspNetUserRoles { get; set; } = null!;
public virtual DbSet<DeltaIdentityRole<int>> AspNetRole { get; set; } = null!;
On Model Creating:
modelBuilder.Entity<DeltaIdentityUser<int>>(entity =>
{
entity.HasOne(d => d.User)
.WithOne(p => p.AspNetUser)
.HasForeignKey<DeltaIdentityUser<int>>(d => d.Id)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_dbo.AspNetUsers_dbo.UserProfiles_UserId");
});
modelBuilder.Entity<DeltaIdentityUserRole<int>>(entity =>
{
entity.HasOne(d => d.User)
.WithMany(p => p.AspNetUserRoles)
.HasForeignKey(d => d.UserId)
.HasConstraintName("FK_dbo.AspNetUserRoles_dbo.UserProfiles_UserId");
});
UserProfile:
public virtual ICollection<DeltaIdentityRole<int>> AspNetRoles { get; set; }
public virtual DeltaIdentityUser<int> AspNetUser { get; set; }
public virtual ICollection<DeltaIdentityUserRole<int>> AspNetUserRoles { get; set; }
Here is need to set many-many relationship with userprofile and AspNetUserRoles:
modelBuilder.Entity<UserProfile>(entity =>
{
entity.HasMany(d => d.AspNetRoles)
.WithMany(p => p.UserProfiles)
.UsingEntity<Dictionary<string, object>>(
"AspNetUserRoles",
l => l.HasOne<DeltaIdentityRole<int>>().WithMany().HasForeignKey("RoleId").HasConstraintName("FK_AspNetUserRoles_AspNetRoles_RoleId"),
r => r.HasOne<UserProfile>().WithMany().HasForeignKey("UserId").HasConstraintName("FK_dbo.AspNetUserRoles_dbo.UserProfiles_UserId")
,
j =>
{
j.ToTable("AspNetUserRoles");
});
}
So now when i try to add migration to generate identity schema i get error
Cannot use table 'AspNetUserRoles' for entity type 'DeltaIdentityUserRole' since it is being used for entity type 'AspNetUserRoles (Dictionary<string, object>)' and potentially other entity types, but there is no linking relationship. Add a foreign key to 'DeltaIdentityUserRole' on the primary key properties and pointing to the primary key on another entity type mapped to 'AspNetUserRoles'.
WHat i need to get done is UserProfile table should have many-many relation with DeltaIdentityUserRole(AspNetUserRoles table)

Entity framework conditional entity relation

UPDATED
I have a Notification table as
public class Notification
{
public int SourceType { get; set; }
public int SourceID { get; set; }
....
// Relations
public virtual SourceA A { get; set; }
public virtual SourceB B { get; set; }
}
and there are two source tables
public class SourceA
{
public int Id { get; set; }
...
public virtual Notification {get; set;}
}
public class SourceB
{
public int Id { get; set; }
...
public virtual Notification {get; set;}
}
In modelbuilder
modelBuilder.Entity<SourceA>()
.HasOptional(c => c.Notification)
.WithRequired(x => x.A);
modelBuilder.Entity<SourceB>()
.HasOptional(c => c.Notification)
.WithRequired(x => x.B);
This is my new query
var myNotification = db.Notifications.Select(x => new Notification()
{
A= x.A,
B= x.B,
SourceID = x.SourceID,
}).ToList(); //error
I am getting this error The entity or complex type 'Notification' cannot be constructed in a LINQ to Entities query
The SourceTypes are A and B. how do i make entity relation in Notification according to the type of Source?
I used linq join on every query to join the related entites according to sourcetypes for now.
I am doing database first model.
You can do it creating a relation 0..1 to many
In SourceA and SourceB you have to add a property to reference to Notification Parent
public virtual Notification { get; set; }
And then create 0..1 to many Relation in you Entity Framework configuration
HasOptional(x => x.SourceA)
.WithRequired(s => s.Notification);
HasOptional(x => x.SourceB)
.WithRequired(s => s.Notification);
Query error
You can't do a Select with a new in a Query that is executed in Database, this only work in memory collections, to have the value of SourceID you can do something like
public int SourceID { get return SourceA = !null ? SourceA.ID : SourceB.ID; }

How do I properly add multiple one-to-one relationships on two tables using Entity Framework?

I want to create a Lighthead class that has two one-to-one relationships with the Lens class. When I map the classes as they are set up below I receive the following error.
The operation failed because an index or statistics with name 'IX_Id' already exists on table 'dbo.Lens'.
How do I fix this?
here is my mapping
public class LensMap : EntityTypeConfiguration<Lens>
{
public LensMap()
{
// Primary Key
this.HasKey(t => t.Id);
// Properties
this.Property(t => t.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
// Table & Column Mappings
this.ToTable("Lens");
this.Property(t => t.Id).HasColumnName("Id");
// Relationships
this.HasRequired(t => t.LightHead)
.WithOptional(t => t.Lens);
this.HasRequired(t => t.LightHead1)
.WithOptional(t => t.Lens1);
}
}
Here is my lens class
public class Lens
{
public int Id { get; set; }
public virtual LightHead LightHead { get; set; }
public virtual LightHead LightHead1 { get; set; }
}
Here is my lighthead class
public class LightHead
{
public int Id { get; set; }
public virtual Lens Lens { get; set; }
public virtual Lens Lens1 { get; set; }
}
Note I am using Entity Framework 6 and C#
also I have tried to do this with one LightHead in the Lens class it returns the following error
Schema specified is not valid. Errors: The relationship 'WebApplication2.Models.LightHead_Lens' was not loaded because the type 'WebApplication2.Models.Lens' is not available.
I believe you need a foreing key here.
// Relationships
this.HasRequired(t => t.LightHead)
.WithOptional(t => t.Lens)
.HasForeignKey(t => t.LightHeadId)
this.HasRequired(t => t.LightHead1)
.WithOptional(t => t.Lens1);
.HasForeignKey(t => t.LightHead1Id)
...
public class Lens
{
public int Id { get; set; }
public int LightHeadId {get;set;}
public int LightHead1Id {get;set;}
public virtual LightHead LightHead { get; set; }
public virtual LightHead LightHead1 { get; set; }
}
public class LightHead
{
public int Id { get; set; }
public virtual Lens Lens { get; set; }
public virtual Lens Lens1 { get; set; }
}
Alternatively you can use Entity Framework table splitting feature to map two entities to single table.
This also lets you query part of your table columns as single entity in order to improve performance.
So Your mapping should be as below
modelBuilder.Entity<LightHead>.HasOptional(x=> x.Lens).WithRequired(a=> a.LightHead);
modelBuilder.Entity<LightHead>.HasOptional(x=> x.Lens1).WithRequired(a => a.LightHead1);
modelBuilder.Entity<Lens>().Property(x=> x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
You need to set databaseGeneratedOption to None becuase Id of Lens will be same as Id of LightHead as in one to one relationship you can't have primary keys in secondary tables.
Secondary entity is treated as extension of primary entity.

How to do a NHibernate many-to-one/one-to-many foreign key in case of navigation property name different from property type?

I'm using NHibernate/FluentNhibernate with AutoMapping configuration and I'm having troubles with foreign keys of some relationships. Especially those where the navigation property name is different from the the name of the type it is pointing to :
public class Country
{
public virtual string Code { get; set; }
public virtual string Name { get; set; }
public virtual Currency DefaultCurrency { get; set; }
}
public class Currency
{
public virtual string Code { get; set; }
public virtual decimal Rate { get; set; }
public virtual IList<Country> Countries { get; set; }
}
In the case of Country entity where the name of navigation property DefaultCurrency is different from the name Currency type. The automapping of NHibernate will guess that the Country table will have the following foreign key:
DefaultCurrency_id: corresponding to the relation of Country.Currency
Currency_id: corresponding to the relation of Currency.Countries
How to tell to the automapping that the relation Currency.Countries can be expressed with DefaultCurrency_id key, resulting to one key foreign only for the Country table:
DefaultCurrency_id: corresponding to the relation of Country.Currency and Currency.Countries
You can specify any column name you want in the mapping.
For references:
References(x => x.Foo, "MyFooId")
For has-many:
HasMany(x => x.Foos)
.KeyColumn("MyFooId")
For many-to-many:
HasManyToMany(x => x.Foos)
.ChildKeyColumn("MyFooId")
.ParentKeyColumn("MyFooId")
You can also use conventions, e.g.:
public class HasManyConventions : IHasManyConvention
{
public void Apply(IOneToManyCollectionInstance target)
{
target.Key.Column(target.EntityType.Name + "Id");
}
}

Categories