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
Related
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");
}
}
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());
}
}
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);
}
}
Adding an entity with 1 level of one to many relationship is pretty straight forward.
using (var dbCtx = new DbContext())
{
dbCtx.Stuff.Add(myObject);
dbCtx.SaveChanges();
}
But how do you add an object with 2 levels? Adding it in the same way omits the 2. level. Which means that the Bar objects (in the example below) isn't saved. What am I doing wrong?
Object graph
Inherited objects
public class BaseEntity
{
public int Id;
// Omitted properites...
}
public class MyEntity : BaseEntity
{
// Omitted properites...
// Navigation properties
public virtual ICollection<Foo> Foos { get; set; }
}
Nested objects (1:M)
public class Foo // 1. level
{
public int Id;
public int MyEntityId;
// Omitted properites...
// Navigation properties
public virtual ICollection<Bar> Bars { get; set; }
public virutal MyEntity MyEntity { get; set; }
}
public class Bar // 2. level
{
public int Id;
public int FooId;
// Omitted properites...
// Navigation properties
public virutal Foo Foo { get; set; }
}
Mapping setup using fluent API
Inherited objects
public class BaseEntityMap : EntityTypeConfiguration<BaseEntity>
{
public BaseEntityMap()
{
// Primary Key
this.HasKey(t => t.Id);
// Properties
// Table & Column Mappings
this.ToTable("BaseEntitySet");
this.Property(t => t.Id).HasColumnName("Id");
// ...
}
}
public class MyEntityMap : EntityTypeConfiguration<MyEntity>
{
public MyEntityMap()
{
// Table & Column Mappings
this.ToTable("BaseEntitySet_MyEntities");
}
}
Nested objects (1:M)
public class FooMap : EntityTypeConfiguration<Foo>
{
public FooMap()
{
// Primary Key
this.HasKey(t => t.Id);
// Table & Column Mappings
this.ToTable("FooSet");
this.Property(t => t.Id).HasColumnName("Id");
this.Property(t => t.MyEntityId).HasColumnName("MyEntity_Id");
// Relationships
this.HasRequired(t => t.MyEntity)
.WithMany(t => t.Foos)
.HasForeignKey(d => d.MyEntityId);
}
}
public class BarMap : EntityTypeConfiguration<Bar>
{
public BarMap()
{
// Primary Key
this.HasKey(t => t.Id);
// Table & Column Mappings
this.ToTable("BarSet");
this.Property(t => t.Id).HasColumnName("Id");
this.Property(t => t.FooId).HasColumnName("Bar_Id");
// Relationships
this.HasRequired(t => t.Foo)
.WithMany(t => t.Bars)
.HasForeignKey(d => d.FooId);
}
}
Repository
public void Add(BaseEntity item)
{
using (var ctx = new DbContext())
{
ctx.BaseEntities.Add(item);
ctx.SaveChanges();
}
}
\Wanted to post my answer in case it helps others, and so the experts can tear it to pieces and post the real answer. For me it did not start working out of the blue :)
If I understand your object graph correctly, it's MyEntity has Foos which has Bars. I had a similar structure, but when calling "SaveChanges" a DbUpdateException would be thrown with a message that
"multiple entities may have the same primary key."
Here's how I made it work for me:
Step 1: Change the Id properties from int to int? and initialize them to null. To me this is a more accurate model than a plain integer. When an entity is new, the ID is literally "undefined or unknown". 0 is a defined number and for some reason EF has a problem with the ID's being the same, even when the records are being added.
public class BaseEntity
{
public BaseEntity()
{
this.Id = null;
}
public int? Id;
// Omitted properites...
}
public class Foo
{
public Foo()
{
this.Id = null;
}
public int? Id;
}
public class Bar
{
public Bar()
{
this.Id = null;
}
public int? Id;
}
Step 2: Add the "DatabaseGeneratedOption.Identity" flag to the Id properties in the mapping. I believe this prevents it from being "required" in the case the entity is added to the datacontext.
public class BaseEntityMap : EntityTypeConfiguration<BaseEntity>
{
public BaseEntityMap()
{
// Primary Key
this.HasKey(t => t.Id);
// Properties
// Table & Column Mappings
this.ToTable("BaseEntitySet");
this.Property(t => t.Id).HasColumnName("Id")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
// ...
}
}
public class FooMap : EntityTypeConfiguration<Foo>
{
public FooMap()
{
// Primary Key
this.HasKey(t => t.Id);
// Table & Column Mappings
this.ToTable("FooSet");
this.Property(t => t.Id).HasColumnName("Id")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.Property(t => t.MyEntityId).HasColumnName("MyEntity_Id");
// Relationships
this.HasRequired(t => t.MyEntity)
.WithMany(t => t.Foos)
.HasForeignKey(d => d.MyEntityId);
}
}
public class BarMap : EntityTypeConfiguration<Bar>
{
public BarMap()
{
// Primary Key
this.HasKey(t => t.Id);
// Table & Column Mappings
this.ToTable("BarSet");
this.Property(t => t.Id).HasColumnName("Id")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.Property(t => t.FooId).HasColumnName("Bar_Id");
// Relationships
this.HasRequired(t => t.Foo)
.WithMany(t => t.Bars)
.HasForeignKey(d => d.FooId);
}
}
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.