EF MVC4 C#: Many to Many Relationship with "relationship property" DB First - c#

I've already spent the last few days trying to fix my problem, sadly without any result. I've already read countless post on here on this subject, but I keep getting the same error. "Unknown column 'Extent1.foo_id' in 'field list'"... What am I doing wrong? My mapping has to be wrong some way, but I fail to see how...
Edit: It's database first!
I also have another class "Doo" which has a many to many relationship with "Foo" but that one is working fine.
Thanks in advance!
public class Foo
{
public Foo()
{
this.FooBoo = new Collection<FooBoo>();
}
public String FooId { get; set; }
public virtual ICollection<FooBoo> FooBoo { get; set; }
}
public class Boo
{
public Boo()
{
this.FooBoo = new Collection<FooBoo>();
}
public String BooId { get; set; }
public virtual ICollection<FooBoo> FooBoo { get; set; }
}
public class FooBoo
{
public String Fooid { get; set; }
public virtual Foo Foo { get; set; }
public String Booid { get; set; }
public virtual Boo Boo { get; set; }
public Boolean RandomProperty { get; set; }
}
public class BooMapper : EntityTypeConfiguration<Boo>
{
public BooMapper()
{
this.HasKey(t => t.BooId);
this.Property(t => t.BooId).HasColumnName("booid");
this.ToTable("boo", "fooboodb");
this.HasMany(t => t.FooBoo)
.WithRequired()
.HasForeignKey(t => t.Booid);
}
}
public class FooMapper : EntityTypeConfiguration<Foo>
{
public FooMapper()
{
this.HasKey(t => t.FooId);
this.Property(t => t.FooId).HasColumnName("fooid");
.
this.ToTable("foo", "fooboodb");
this.HasMany(t => t.FooBoo)
.WithRequired()
.HasForeignKey(t => t.Booid);
}
}
public class FooBooMapper : EntityTypeConfiguration<FooBoo>
{
public FooBooMapper()
{
this.HasKey(t => new {t.Fooid, t.Booid});
this.Property(t => t.Fooid);
this.Property(t => t.Booid);
this.Property(t => t.RandomProperty);
this.ToTable("fooboo", "fooboodb");
this.Property(t => t.Fooid).HasColumnName("Fooid");
this.Property(t => t.Booid).HasColumnName("Booid");
this.Property(t => t.RandomProperty).HasColumnName("randomproperty");
}
}

You must provide a lambda expression for the two WithRequired calls in order to specify the inverse navigation properties. Otherwise EF will assume that they belong to another additional relationship which is causing those foreign keys with underscores:
public class BooMapper : EntityTypeConfiguration<Boo>
{
public BooMapper()
{
//...
this.HasMany(t => t.FooBoo)
.WithRequired(fb => fb.Boo)
.HasForeignKey(t => t.Booid);
}
}
public class FooMapper : EntityTypeConfiguration<Foo>
{
public FooMapper()
{
//...
this.HasMany(t => t.FooBoo)
.WithRequired(fb => fb.Foo)
.HasForeignKey(t => t.Booid);
}
}

Related

One to one relationship Entity Framework foreign key mapping

I am working on assigning a relationship between two objects but I am getting an error on the mapping.
I have the following objects:
public abstract class EntityBase : IEntity
{
public int Id { get; set; }
}
public class ManagerUser : EntityBase
{
public string UserCode { get; set; }
public string Title { get; set; }
public virtual Staff StaffDetails { get; set; }
}
public class Staff : EntityBase
{
public string UserCode { get; set; }
public string DOB { get; set; }
}
public class ManagerUserMap : EntityMapBase<ManagerUser>
{
protected override void SetupMappings()
{
base.SetupMappings();
//this.HasKey(t => t.UserCode);
this.ToTable("ManagerUsers");
this.Property(t => t.Id).HasColumnName("ManagerUsersID")
.HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);
this.Property(t => t.Title).HasColumnName("txtTitle");
this.HasRequired(x => x.StaffDetails)
.WithMany()
.HasForeignKey(x => x.UserCode);
}
}
public class StaffMap : EntityMapBase<Staff>
{
protected override void SetupMappings()
{
base.SetupMappings();
//this.HasKey(t => t.UserCode);
this.ToTable("TblStaff");
this.Property(t => t.Id).HasColumnName("StaffID")
.HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);
this.Property(t => t.UserCode).HasColumnName("User_Code");
this.Property(t => t.DateOfBirth).HasColumnName("dob");
}
}
I am getting the following error:
The type of property 'UserCode' on entity 'ManagerUser' does not match
the type of property 'Id' on entity 'Staff' in the referential
constraint 'ManagerUser_StaffDetails'
I have searched around and failed to find a solution to get it to compare the the foreign key in ManagerUser with the UserCode property in Staff instead of the ID property.
Your keys are a bit messed up in the fluent config, HasKey sets the primary key for the entity. Below I have set the primary key to be Id for both entities. Then use the Usercode as a FK:
public class ManagerUserMap : EntityMapBase<ManagerUser>
{
protected override void SetupMappings()
{
base.SetupMappings();
this.HasKey(t => t.Id);
this.ToTable("ManagerUsers");
this.Property(t => t.Id).HasColumnName("ManagerUsersID")
.HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);
this.Property(t => t.Title).HasColumnName("txtTitle");
this.HasRequired(x => x.StaffDetails)
.WithMany()
.HasForeignKey(x => x.UserCode);
}
}
public class StaffMap : EntityMapBase<Staff>
{
protected override void SetupMappings()
{
base.SetupMappings();
this.HasKey(t => t.Id);
this.ToTable("TblStaff");
this.Property(t => t.Id).HasColumnName("StaffID")
.HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);
this.Property(t => t.UserCode).HasColumnName("User_Code");
this.Property(t => t.DateOfBirth).HasColumnName("dob");
}
}

Entity Framework TPH bug

I have this Entity :
public class Soggetti
{
public Soggetti()
{
}
public int sersog { get; set; }
string descri { get; set; }
}
public class SoggettiMap : EntityTypeConfiguration<Soggetti>
{
public SoggettiMap()
{
// Primary Key
this.HasKey(t => t.sersog);
this.Property(t => t.descri)
.IsFixedLength()
.HasMaxLength(200);
this.ToTable("soggetti");
this.Property(t => t.sersog).HasColumnName("sersog");
this.Property(t => t.descri).HasColumnName("descri");
}
}
And this:
public class Enti : Soggetti
{
public Enti()
{
}
public int serent { get; set; }
public string denuff { get; set; }
}
public class entiMap : EntityTypeConfiguration<Enti>
{
public entiMap()
{
// Primary Key
this.HasKey(t => t.serent);
// Properties
this.Property(t => t.denuff)
.HasMaxLength(150);
// Table & Column Mappings
this.ToTable("enti");
this.Property(t => t.denuff).HasColumnName("denuff");
this.Property(t => t.serent).HasColumnName("serent");
}
}
If try this linq code :
from e in Enti select e
result is ok, nut if try this :
Enti.Find(1)
I have an error because where's sql code goes by sersog and not serent
WHERE [Extent1].[sersog] = #p0
In the Enti's entity map i've defined serent with HasKey property and not sersog that is defined with HasKey property in soggetti class

Entity Framework 6 cross reference table

To all, thank you for your help in advance.
I am unable to correctly update the cross reference table using my Data-context in Entity Framework 6 that links the two entity tables .
Within my ObjectRepository, when I make the call to my datacontext to update the database, i.e. "db.SaveChanges(); , I get an INNER EXCEPTION
"Cannot insert explicit value for identity column in table 'SN_Tags' when IDENTITY_INSERT is set to OFF."
That error makes sense because, as it is defined now, my Datacontext is attempting to insert records into my SN_Tags table, which is a table that is already populated with Tags that I want to link to my SN_Objects. The table that should get a record, or records inserted into it when an SN_Object is added to the database, is the SN_ObjectTags link table. I've attempted to explain the structure below. I hope this isn't too long.
Thank you for the help.
E_Rog
SN_Objects An SN_Object entity can have many tags.
Columns: ObjectID, ObjectDesc, ModuleID.. etc
public partial class SNObject
{
public SNObject()
{
this.SN_Tags = new List<Tag>();
}
public int ObjectID { get; set; }
public string ObjectDesc { get; set; }
public int ModuleID { get; set; }
......
public virtual ICollection<Tag> SN_Tags { get; set; }
}
SN_Tags A Tag entity can be linked to many SN_Objects This table is already populated with the list of tags that will be checked to see if an SN_Object should be linked to a particular Tag or Tags.
Columns: TagID, TagDesc, IsActive
public partial class Tag
{
public Tag()
{
//this.SN_Objects = new List<SNObject>();
}
public int TagID { get; set; }
public string TagDesc { get; set; }
public bool IsActive { get; set; }
public virtual ICollection<SNObject> SN_Objects { get; set; }
}
SN_ObjectTags Cross reference table for the many to many relationship
Columns: ObjectID, TagID
As you know, no Entity exists for this Cross Reference table.
NOW,, here's the Mapping class files, with a few extra details referencing properties I didn't include in the Entity class files above, but the key stuff is there.
SN_ObjectsMap
public class SN_ObjectsMap : EntityTypeConfiguration<SNObject>
{
public SN_ObjectsMap()
{
// Primary Key
this.HasKey(t => t.ObjectID);
// Properties
this.Property(t => t.ObjectDesc)
.IsRequired()
.HasMaxLength(200);
this.Property(t => t.BankNameShort)
.IsRequired()
.HasMaxLength(255);
// Table & Column Mappings
this.ToTable("SN_Objects");
this.Property(t => t.ObjectID).HasColumnName("ObjectID");
this.Property(t => t.ObjectDesc).HasColumnName("ObjectDesc");
this.Property(t => t.ModuleID).HasColumnName("ModuleID");
this.Property(t => t.BankNameShort).HasColumnName("BankNameShort");
this.Property(t => t.SubModuleID).HasColumnName("SubModuleID");
// Relationships
this.HasMany(t => t.SN_Tags)
.WithMany(t => t.SN_Objects)
.Map(m =>
{
m.ToTable("SN_ObjectTags");
m.MapLeftKey("ObjectID");
m.MapRightKey("TagID");
});
this.HasRequired(t => t.TN_Banks)
.WithMany(t => t.SN_Objects)
.HasForeignKey(d => d.BankNameShort);
this.HasRequired(t => t.TN_Modules)
.WithMany(t => t.SN_Objects)
.HasForeignKey(d => d.ModuleID);
}
}
SN_TagsMap
public class SN_TagsMap : EntityTypeConfiguration<Tag>
{
public SN_TagsMap()
{
// Primary Key
this.HasKey(t => t.TagID);
// Properties
this.Property(t => t.TagID)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.Property(t => t.TagDesc)
.IsRequired()
.HasMaxLength(256);
// Table & Column Mappings
this.ToTable("SN_Tags");
this.Property(t => t.TagID).HasColumnName("TagID");
this.Property(t => t.TagDesc).HasColumnName("TagDesc");
this.Property(t => t.IsActive).HasColumnName("IsActive");
}
}
And Finally an abbreviated DataContext
public partial class MyContext : DbContext
{
static MyContext()
{
Database.SetInitializer<MyContext>(null);
}
public MyContext() : base("Name=MyContext")
{
}
public DbSet<CPR> SN_ObjectCPRs { get; set; }
public DbSet<File> SN_ObjectFiles { get; set; }
public DbSet<SNObject> SN_Objects { get; set; }
public DbSet<Tag> SN_Tags { get; set; }
public DbSet<sysdiagram> sysdiagrams { get; set; }
public DbSet<Bank> TN_Banks { get; set; }
public DbSet<Module> TN_Modules { get; set; }
public DbSet<SubModule> TN_SubModules { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new SN_ObjectCPRsMap());
modelBuilder.Configurations.Add(new SN_ObjectFilesMap());
modelBuilder.Configurations.Add(new SN_ObjectsMap());
modelBuilder.Configurations.Add(new SN_TagsMap());
modelBuilder.Configurations.Add(new sysdiagramMap());
modelBuilder.Configurations.Add(new TN_BanksMap());
modelBuilder.Configurations.Add(new TN_ModulesMap());
modelBuilder.Configurations.Add(new TN_SubModulesMap());
}
}

Mapping by code Zero-Or-One relationship

I have the following database structure, which I cannot change:
CREATE TABLE Users (
ID INT NOT NULL IDENTITY(1,1),
PRIMARY KEY(ID)
)
CREATE TABLE UserAvatars (
UserID INT NOT NULL,
Width INT NOT NULL,
Height INT NOT NULL,
PRIMARY KEY(UserID),
FOREIGN KEY(UserID) REFERENCES Users(ID),
)
Basically, a User can have Zero-or-one avatars (I removed columns to simplify the example).
class User
{
public int ID { get; protected set; }
public UserAvatar Avatar { get; set; }
}
class UserAvatar
{
public User User { get; set; }
public int Width { get; set; }
public int Height { get; set; }
}
I am using the following mapping:
class UserMapping : ClassMapping<User>
{
public UserMapping()
{
Id(x => x.ID, m => {
m.Generator(Generators.Identity);
});
OneToOne(x => x.Avatar);
}
}
class UserAvatarMapping : ClassMapping<UserAvatar>
{
public UserAvatar()
{
Id(x => x.User, m =>
{
m.Generator(Generators.Foreign<User>(u => u.ID));
});
Property(x => x.Width);
Property(x => x.Height);
}
}
However, when trying run my app, I get an NHibernate.MappingException:
NHibernate.MappingException : Could not compile the mapping document:
mapping_by_code----> NHibernate.MappingException : Could not determine
type for: MyApp.Models.UserAvatar, MyApp, for columns:
NHibernate.Mapping.Column(User)
I can't make any sense of this cryptic error.
How do I accomplish the mapping where a User could have zero or one Avatars?
Taking from Radim Köhler's guidence, the final classes / mapping that solved the problem:
class User
{
public int ID { get; protected set; }
public UserAvatar Avatar { get; set; }
}
class UserAvatar
{
public int UserID { get; protected set; }
public User User { get; set; }
public int Width { get; set; }
public int Height { get; set; }
}
With the following mapping:
class UserMapping : ClassMapping<User>
{
public UserMapping()
{
Id(x => x.ID, m => {
m.Generator(Generators.Identity);
});
OneToOne(x => x.Avatar, m =>
{
m.Cascade(Cascade.All);
m.Constrained(false);
});
}
}
class UserAvatarMapping : ClassMapping<UserAvatar>
{
public UserAvatar()
{
Id(x => x.UserID, m =>
{
m.Generator(Generators.Foreign<UserAvatar>(u => u.User));
});
OneToOne(x => x.User, m =>
{
m.Constrained(true);
});
Property(x => x.Width);
Property(x => x.Height);
}
}
The ID is important almost for every entity mapped by NHibernate (ORM). So, we should extend the Avatar class:
class UserAvatar
{
// every(stuff) should have its ID
public int ID { get; protected set; }
public User User { get; set; }
...
The ID value will be managed by one-to-one relationship. So, now let's adjust the mapping.
public UserAvatar()
{
Id(x => x.ID);
HasOne(x => x.User)
.Constrained()
.ForeignKey();
...
public UserMapping()
{
Id(x => x.ID);
HasOne(s => s.Avatar).Cascade.All();
Related and really interesting reading:
How to do a fluent nhibernate one to one mapping?
Fluent NHibernate & HasOne(): how to implement a one-to-one relationship

Abstract domain model base class when using EntityTypeConfiguration<T>

Is there some trick to getting a central mapping of Base object properties?
Is there some simple pattern for abstract classes when using EntityTypeConfiguration.
ANy tips much appreciated.
Im unable to declare a class
Public class BaseEntityConfig<T> : EntityTypeConfiguration<T>
Similar issues, where i couldnt get the answers to work
How to create and use a generic class EntityTypeConfiguration<TEntity>
and
Dynamic way to Generate EntityTypeConfiguration : The type 'TResult' must be a non-nullable value type
public abstract class BosBaseObject
{
public virtual Guid Id { set; get; }
public virtual string ExternalKey { set; get; }
public byte[] RowVersion { get; set; }
}
public class News : BosBaseObject
{
public String Heading { set; get; }
}
public class NewsMap : EntityTypeConfiguration<News>
{
public NewsMap()
{
//Base Object Common Mappings
// How can we use a central mapping for all Base Abstract properties
}
}
// Something like this but very open to any suggestion....
public class BosBaseEntityConfig<T> : EntityTypeConfiguration<T>
{
public void BaseObjectMap( )
{
// Primary Key
this.HasKey(t => t.Id);
// Properties
this.Property(t => t.Id).HasDatabaseGeneratedOption(databaseGeneratedOption: DatabaseGeneratedOption.None);
this.Property(t => t.RowVersion)
.IsRequired()
.IsFixedLength()
.HasMaxLength(8)
.IsRowVersion();
//Column Mappings
this.Property(t => t.Id).HasColumnName("Id");
}
}
The answer above definitely works, though this may be slight cleaner and has the advantage of working the same when registering the configurations in the DbContext.
public abstract class BaseEntity
{
public int Id { get; set; }
}
public class Company : BaseEntity
{
public string Name { get; set; }
}
internal class BaseEntityMap<T> : EntityTypeConfiguration<T> where T : BaseEntity
{
public BaseEntityMap()
{
// Primary Key
HasKey(t => t.Id);
}
}
internal class CompanyMap : BaseEntityMap<Company>
{
public CompanyMap()
{
// Properties
Property(t => t.Name)
.IsRequired()
.HasMaxLength(256);
}
}
public class AcmeContext : DbContext
{
public DbSet<Company> Companies { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new CompanyMap());
}
}
Above solution arrived at by Christian Williams and myself early one morning...
After 6 hrs I cracked it. I think it is a reasonably clean outcome.
The trick is to forget doing every inside a class derived from EntityTypeConfiguration
and build a custom BaseConfig and then to take this instance and add the specifics for this class. Hope it helps others doing code first with abstracts...
public abstract class BosBaseObject
{
public virtual Guid Id { set; get; }
public virtual string ExternalKey { set; get; }
public byte[] RowVersion { get; set; }
}
public abstract class BosObjectDateManaged : BosBaseObject
{
public DateTimeOffset ValidFrom { set; get; }
public DateTimeOffset ValidTo { set; get; }
}
public class News : BosObjectDateManaged
{
public String Heading { set; get; }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var conf = new BosBaseEntityConfiguration<News>();//Construct config for Type
modelBuilder.Configurations.Add( conf ); // this has base mapping now
var newsConf = new NewsConfiguration(conf); // now the Object specific properties stuff
}
}
public class BosBaseEntityConfiguration<T> : EntityTypeConfiguration<T> where T : BosBaseObject
{
public BosBaseEntityConfiguration()
{
// Primary Key
this.HasKey(t => t.Id);
//// Properties
this.Property(t => t.Id).HasDatabaseGeneratedOption(databaseGeneratedOption: DatabaseGeneratedOption.None);
this.Property(t => t.RowVersion)
.IsRequired()
.IsFixedLength()
.HasMaxLength(8)
.IsRowVersion();
//Column Mappings
this.Property(t => t.Id).HasColumnName("Id");
}
}
public class NewsConfiguration
{
public NewsConfiguration(BosBaseEntityConfiguration<News> entity)
{
// Table Specific & Column Mappings
entity.ToTable("News2");
entity.Property(t => t.Heading).HasColumnName("Heading2");
}
}
Sorry I cannot comment but I would do as you are doing only swap these two lines around
modelBuilder.Configurations.Add( conf ); // this has base mapping now
var newsConf = new NewsConfiguration(conf); // now the Object specific properties stuff
to
new NewsConfiguration(conf); // now the Object
modelBuilder.Configurations.Add( conf ); // this has base mapping now
This helps EF with specialised fields.

Categories

Resources