Entity Framework 6 cross reference table - c#

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());
}
}

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");
}
}

EntityFramework - Table per Type (TPT) Inheritance and Mapping Relationships with CodeFirst

I have the following Entities which I am persisting using EntityFramework CodeFirst:
public class User {
RedGroup RedGroup { get; protected set; }
virtual ICollection<GreenGroup> GreenGroups { get; }
int Id { get; protected set; }
int? RedGroupId { get; protected set; }
}
public abstract class Group {
int Id { get; protected set; }
virtual ICollection<User> Users { get; protected set; }
}
public class RedGroup : Group {
// Other properties
}
public class GreenGroup : Group {
// Other properties
}
Essentially, the user can belong to zero or one red groups, and more than one green group. Each group has a collection of users that belong to it.
I am trying to set up EF using CodeFirst with TPT and am having trouble sorting the mappings. At the moment, I have the following in OnModelCreating:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new RedGroupMap());
modelBuilder.Configurations.Add(new GreenGroupMap());
modelBuilder.Configurations.Add(new UserMap());
}
These are the mapping classes:
public abstract class GroupMap<T> : EntityTypeConfiguration<T>
where T : Group {
public GroupMap() {
this.ToTable("Groups");
this.HasKey(t => t.Id);
this.Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).HasColumnName("Id");
// Also has other non-relationship mappings
}
}
public class RedGroupMap() : GroupMap<RedGroup> {
public RedGroupMap() {
this.ToTable("RedGroups");
// Also has other non-relationship mappings
}
}
public class GreenGroupMap() : GroupMap<GreenGroup> {
public GreenGroupMap() {
this.ToTable("GreenGroups");
this.HasMany(c => c.Users)
.WithMany(p => p.GreenGroups)
.Map(m =>
{
m.MapLeftKey("GreenGroupId");
m.MapRightKey("UserId");
m.ToTable("Users_GreenGroups");
});
// Also has other non-relationship mappings
}
}
public class UserMap() : EntityTypeConfiguration<User> {
this.ToTable("Users");
this.HasKey(t => t.Id);
this.Property(t => t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).HasColumnName("Id");
this.HasOptional(t => t.RedGroup)
.WithMany(t => t.Users)
.Map(x => x.MapKey("RedGroupId"))
.WillCascadeOnDelete(false);
}
I am getting the following runtime error:
Users: FromRole: NavigationProperty 'Users' is not valid. Type 'RedGroup' of FromRole 'User_RedGroup_Target' in AssociationType 'User_RedGroup' must exactly match with the type 'GreenGroup' on which this NavigationProperty is declared on.
Afraid I'm stumped on how to set up this.
How can I set up the EntityFramework mappings to allow a Table per Type hierarchy?
I created a context without your mappings, but with a much simpler configuration and everything appeared to create OK:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Group>().ToTable("Groups");
modelBuilder.Entity<RedGroup>().ToTable("RedGroups");
modelBuilder.Entity<GreenGroup>().ToTable("GreenGroups");
}
I've noticed that you've defined [User].HasOptional(t => t.RedGroup), but the RedGroupId field on User is defined as int and not int? - perhaps this is related?
public class User {
int? RedGroupId { get; protected set; } // int -> int?
RedGroup RedGroup { get; protected set; } // virtual missing, but shouldn't matter
// Other properties
}
If RedGroup is required, try using .HasRequired instead.

Foreign key one to one with Entity Framework

The Customer can have only one Language. I don't find the right way to create the key. When I get an object Customer the property LanguageId has a content but not the property Language. I use EF 6.1
This Language object will be use in other object.
I did this :
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Configurations.Add(new CustomerMap());
modelBuilder.Configurations.Add(new LanguageMap());
}
public class Customer
{
public int CustomerID { get; set; }
public string Code { get; set; }
public int LanguageId { get; set; }
[ForeignKey("LanguageId")]
public Language Language { get; set; }
}
public class CustomerMap : EntityTypeConfiguration<Customer>
{
public CustomerMap()
{
this.HasKey(t => t.CustomerID);
// Properties
this.Property(t => t.CustomerID).IsRequired();
this.Property(t => t.Code).IsRequired();
// Table & Column Mappings
this.ToTable("Customer");
this.Property(t => t.CustomerID).HasColumnName("CustomerID");
this.Property(t => t.Code).HasColumnName("Code");
}
}
public class Language
{
public int LanguageID { get; set; }
public string Code { get; set; }
}
public class LanguageMap : EntityTypeConfiguration<Language>
{
public LanguageMap()
{
this.HasKey(t => t.LanguageID);
this.Property(t => t.Code).IsRequired();
}
}
Update (Language will be used in other object)
You can achieve one to one with two options, but first you have to remove the foreign key value in the principal. Principal means that the record must exist first, that's why this entity doesn't need to have foreign key value, just foreign key reference.
Remove this code.
public int LanguageId { get; set; }
[ForeignKey("LanguageId")]
First. After removing above code add this configuration.
modelBuilder.Entity<Customer>()
.HasRequired(a => a.Language)
.WithRequiredPrincipal();
Second, also add the foreign key reference on dependent (Language).
public Customer Customer { get; set; }
Then mention the principal reference in WithRequiredPrincipal.
modelBuilder.Entity<Customer>()
.HasRequired(a => a.Language)
.WithRequiredPrincipal(x => x.Customer);
update
To load language you can do it with lazy loading by adding virtual keyword (the context configuration must also enable lazy loading and proxy).
public virtual Language Language { get; set; }
Or do with eager loading.
var customerID = 5;
var customer = db.Set<Customer>().Include(c => c.Language)
.FirstOrDefault(c => c.CustomerID == customerID);

Entity Framework 4 - Many-To-Many Relationship with a view

I have an entity Group which has a many to many relationship with a view VesselInfo. In database, the relationship is stored in a table, GroupVessel.
public class Group
{
public Group()
{
GroupVessels = new List<GroupVessel>();
}
public int GroupId { get; set; }
public virtual ICollection<GroupVessel> GroupVessels { get; set; }
}
public class GroupVessel
{
public int GroupVesselId { get; set; }
public int GroupId { get; set; }
public virtual Group Group { get; set; }
public int VesselId { get; set; }
public virtual VesselView Vessel { get; set; }
}
public class VesselView
{
public int VesselId { get; set; }
}
The entities are mapped in the context like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new VesselViewMapping());
modelBuilder.Configurations.Add(new GroupMapping());
modelBuilder.Configurations.Add(new GroupVesselMapping());
base.OnModelCreating(modelBuilder);
}
public class VesselViewMapping : EntityTypeConfiguration<VesselView>
{
public VesselViewMapping()
{
// Primary Key
HasKey(t => t.VesselId);
// Properties
Property(t => t.VesselId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
// Table & Column Mappings
ToTable("v_VesselInfo");
Property(t => t.VesselId).HasColumnName("VesselId");
}
}
public class GroupMapping : EntityTypeConfiguration<Group>
{
public GroupMapping()
{
// Primary Key
HasKey(group => group.GroupId);
// Properties
// Table & Column Mappings
ToTable("Group");
Property(t => t.GroupId)
.HasColumnName("GroupId")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
public class GroupVesselMapping : EntityTypeConfiguration<GroupVessel>
{
public GroupVesselMapping()
{
// Primary Key
HasKey(group => group.GroupVesselId);
// Properties
// Table & Column Mappings
ToTable("GroupVessel");
Property(t => t.GroupVesselId)
.HasColumnName("GroupVesselId")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(t => t.VesselId).HasColumnName("VesselId").IsRequired();
Property(t => t.GroupId).HasColumnName("GroupId");
// Relationships
HasRequired(t => t.Group).WithMany(g => g.GroupVessels)
.HasForeignKey(t => t.GroupVesselId);
}
}
When I try to instantiate the context, I get the following error:
Exception Details: System.Data.Entity.ModelConfiguration.ModelValidationException: One or more validation errors were detected during model generation:
\tSystem.Data.Entity.Edm.EdmAssociationEnd: : Multiplicity is not valid in Role 'GroupVessel_Group_Source' in relationship 'GroupVessel_Group'. Because the Dependent Role refers to the key properties, the upper bound of the multiplicity of the Dependent Role must be '1'.
Some additional info:
In database, the GroupVessel.VesselId column is a foreign key to a table Vessels, which is the underlying table of the v_VesselInfo view. There is no navigation property from VesselView back to GroupVessel as there is no need to traverse the graph that way in the application.
Finally figured it out, I used the wrong field as the foreign key field, changed to GroupId and it works

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

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);
}
}

Categories

Resources