Entity Framework TPH Inheritance errors: - entity-framework

I get the error message;
error 3032: Problem in mapping fragments starting at line 77:Condition member 'Company.CompanyTypeId' with a condition other than 'IsNull=False' is mapped. Either remove the condition on Company.CompanyTypeId or remove it from the mapping.
I have done a search on how to fix, this but I do not understand the answers.
My classes are
public abstract class Company
{
public Company()
{
this.AddressLines = new List<AddressLine>();
}
public int CompanyId { get; set; }
public int CompanyTypeId { get; set; }
public string Comments { get; set; }
public DateTime? EndOfBusinessDate { get; set; }
public virtual CompanyType CompanyType { get; set; }
}
public class Subcontractor : Company
{
public Subcontractor()
{
this.SubcontractorTrades = new List<SubcontractorTrade>();
}
public virtual ICollection<SubcontractorTrade> SubcontractorTrades { get; set; }
public string ValueOfWork { get; set; }
public string QualityAssured { get; set; }
public int? NumberOfOperatives { get; set; }
public static IPagedList<Subcontractor> GetSubcontractors(int page, int PageSize)
{
using (var db = new SherryGreenGroupContext())
{
return db.Subcontractors
.Include("SubcontractorTrades")
.Include("AddressLines")
.Where(x => x.EndOfBusinessDate == null)
.OrderBy(x => x.Company1)
.ToPagedList(page, PageSize);
}
}
}
My mappings look like;
public CompanyMap()
{
// Primary Key
this.HasKey(t => t.CompanyId);
// Properties
this.Property(t => t.Comments).HasMaxLength(1023);
// Table & Column Mappings
this.ToTable("Company");
this.Property(t => t.CompanyId).HasColumnName("CompanyId");
this.Property(t => t.CompanyTypeId).HasColumnName("CompanyTypeId");
this.Property(t => t.Comments).HasColumnName("Comments");
this.Property(t => t.Created).HasColumnName("Created");
// Relationships
this.HasRequired(t => t.CompanyType).WithMany(t => t.Companies).HasForeignKey(d => d.CompanyTypeId);
}
}
public class SubcontractorMap : EntityTypeConfiguration<Subcontractor>
{
public SubcontractorMap()
{
this.Property(t => t.QualityAssured).IsFixedLength().HasMaxLength(1);
this.Property(t => t.ValueOfWork).HasMaxLength(255);
this.Property(t => t.QualityAssured).HasColumnName("QualityAssured");
this.Property(t => t.ValueOfWork).HasColumnName("ValueOfWork");
this.Property(t => t.NumberOfOperatives).HasColumnName("NumberOfOperatives");
}
}
The context class looks like
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new CompanyMap());
modelBuilder.Configurations.Add(new SubcontractorMap());
modelBuilder.Configurations.Add(new SupplierMap());
modelBuilder.Configurations.Add(new ArchitectsAndSurveyorMap());
modelBuilder.Configurations.Add(new StructuralEngineerMap());
modelBuilder.Configurations.Add(new CostConsultantMap());
modelBuilder.Configurations.Add(new ServiceEngineerMap());
modelBuilder.Configurations.Add(new CompanyTypeMap());
modelBuilder.Entity<Company>()
.Map<Subcontractor>(m => m.Requires("CompanyTypeId").HasValue(4))
.Map<Supplier>(m => m.Requires("CompanyTypeId").HasValue(5))
.Map<ArchitectsAndSurveyor>(m => m.Requires("CompanyTypeId").HasValue(1))
.Map<StructuralEngineer>(m => m.Requires("CompanyTypeId").HasValue(2))
.Map<CostConsultant>(m => m.Requires("CompanyTypeId").HasValue(3))
.Map<ServiceEngineer>(m => m.Requires("CompanyTypeId").HasValue(6));
}
}
I have tried commentinout out CompanyTypeId from both the class definition and the mapping code, but I get the same error

If you want to use CompanyTypeId as discriminator for TPH you must not use it for anything else => you cannot have it as property in Company class and you cannot have relation with CompanyType class. The reason is that entity type in inheritance is immutable. Changing either CompanyTypeId or CompanyType in Company class would change the type of the entity but you cannot change the type of existing instance.

Related

Entity Framework mysterious error

Please help. I don`t understand why from my entity context
var stagesExist = context.WfwDocumentWorkStages
.Any(it => it.Enabled && it.ExecutionId == execution.Id
&& it.Level == execution.Level && it.ResultId == null);
value stagesExist is false
But
var stages = context.WfwDocumentWorkStages.Where(it => it.Enabled
&& it.ExecutionId == execution.Id
&& it.Level == execution.Level).ToList();
bool stagesExist = stages.Any(it=>it.ResultId == null);
value stagesExist is true??
Model:
public partial class WfwDocumentWorkScheme : EnabledEntity
{
public WfwDocumentWorkScheme()
{
this.WfwExecutionEvents = new List<WfwExecutionEvent>();
}
public int ExecutionId { get; set; }
public int Level { get; set; }
public int? RoleId { get; set; }
public string CoordinatorSid { get; set; }
public DateTimeOffset? Date { get; set; }
public int? ResultId { get; set; }
public string Comment { get; set; }
public virtual Employee Coordinator { get; set; }
public virtual EmployeeRole EmployeeRole { get; set; }
public virtual WfwEventResult WfwEventResult { get; set; }
public virtual WfwDocumentExecution WfwDocumentExecution { get; set; }
public virtual ICollection<WfwExecutionEvent> WfwExecutionEvents { get; set; }
}
Mapping
public class WfwDocumentWorkSchemeMap : EntityTypeConfiguration<WfwDocumentWorkScheme>
{
public WfwDocumentWorkSchemeMap()
{
// Primary Key
this.HasKey(t => t.Id);
// Properties
this.Property(t => t.CoordinatorSid)
.HasMaxLength(46);
// Table & Column Mappings
this.ToTable("WfwDocumentWorkSchemes");
this.Property(t => t.Id).HasColumnName("Id");
this.Property(t => t.ExecutionId).HasColumnName("ExecutionId");
this.Property(t => t.Level).HasColumnName("Level");
this.Property(t => t.RoleId).HasColumnName("RoleId");
this.Property(t => t.CoordinatorSid).HasColumnName("CoordinatorSid");
this.Property(t => t.Date).HasColumnName("Date");
this.Property(t => t.ResultId).HasColumnName("ResultId");
this.Property(t => t.Comment).HasColumnName("Comment");
this.Property(t => t.Enabled).HasColumnName("Enabled");
// Relationships
this.HasRequired(t => t.Coordinator)
.WithMany(t => t.WfwDocumentWorkSchemes)
.HasForeignKey(d => d.CoordinatorSid);
this.HasRequired(t => t.WfwDocumentExecution)
.WithMany(t => t.WfwDocumentWorkSchemes)
.HasForeignKey(d => d.ExecutionId);
this.HasRequired(t => t.WfwEventResult)
.WithMany(t => t.WfwDocumentWorkSchemes)
.HasForeignKey(d => d.ResultId);
this.HasOptional(t => t.EmployeeRole)
.WithMany(t => t.WfwDocumentWorkSchemes)
.HasForeignKey(d => d.RoleId);
}
}
Result model contains virtual List
public class WfwEventResult : EnabledEntity
{
public WfwEventResult()
{
this.WfwExecutionEvents = new List<WfwExecutionEvent>();
this.WfwDocumentWorkSchemes = new List<WfwDocumentWorkScheme>();
}
public string Name { get; set; }
public string Description { get; set; }
public bool Success { get; set; }
public virtual ICollection<WfwExecutionEvent> WfwExecutionEvents { get; set; }
public virtual ICollection<WfwDocumentWorkScheme> WfwDocumentWorkSchemes { get; set; }
}
The problem is this line in your mapping:
this.HasRequired(t => t.WfwEventResult)
You are effectively telling the EF that the associated FK column will never be null (although you've made it int? and have records with null value). Remember that EF uses metadata information when building SQL queries, and in this case I guess the query optimizer decides that this query will never return records (similar to .Where(it => false)) and generates a fake SQL query you see.
Shortly - make sure you always provide the correct information to EF. In this case, change the above to
this.HasOptional(t => t.WfwEventResult)
and you'll see a different (real) query and get a correct results.

Mapping relationships that require a navigation property only on one side

I have this model:
public class Blog
{
public int ID { get; set; }
public string Title { get; set; }
}
public class Post
{
public int ID { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogID { get; set; }
public Blog Blog { get; set; }
}
which has this configuration:
public class BlogMap : EntityTypeConfiguration<Blog>
{
public BlogMap()
{
this.ToTable("Blogs", "dbo");
this.HasKey(t => t.ID);
this.Property(t => t.ID).HasColumnName("ID");
this.Property(t => t.Title).HasColumnName("Title");
}
}
public class PostMap : EntityTypeConfiguration<Post>
{
public PostMap()
{
this.ToTable("Posts", "dbo");
this.HasKey(t => t.ID);
this.Property(t => t.ID).HasColumnName("ID");
this.Property(t => t.Title).HasColumnName("Title");
this.Property(t => t.Content).HasColumnName("Content");
this.Property(t => t.BlogID).HasColumnName("BlogID");
this.HasRequired(t => t.Blog)
.WithRequiredDependent()
.Map(???);
}
}
How do I map this?
I'm guessing that if, like a normal blog, each blog can have many posts, then maybe you need to be configuring a one-to-many relationship:
this.HasRequired(t => t.Blog)
.WithMany() // no arguments means no inverse property
.HasForeignKey(t => t.BlogID);
As an aside, EF will probably be able to infer this relationship even if you don't configure it, but explicitly configuring it is perfectly fine.

Entity Framework codefirst issueUnable to determine the principal end of an association between the types

So I'm trying to use the MVC 4 internet application template and the UserProfile database tables it creates for accounts and then add tables that have dependencies on the UserProfile table for additional information.
The model would be UserProfile 0 ---> 1 UserType1 and UserProfile 0 ----> UserType2
where the userprofile table may have a dependent record in UserType1 and may have a dependent record in UserType2 and if there is an entry in either UserType1 or UserType2 its primary key is a foreign key that is the UserId from User Profiles
The POCO is:
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string Email { get; set; }
public string UserName { get; set; }
public int type { get; set; }
public virtual UserType1 UserType1 { get; set; }
public virtual UserType2 UserType2 { get; set; }
public class UserType1
{
[key,ForeignKey("UserProfile")]
public virtual int UserId {get;set;}
public int myval {get;set;}
public UserProfile UserProfile {get; set;}
}
public class UserType2 //same as usertype 1
I've tried adding model mapping statements but to no avail
Model mapping data for user profile:
public class UserProfileMap : EntityTypeConfiguration<UserProfile>
{
public UserProfileMap()
{
// Primary Key
this.HasKey(t => t.UserId);
// Properties
this.Property(t => t.Email)
.IsRequired()
.HasMaxLength(56);
this.Property(t => t.UserName)
.IsRequired()
.HasMaxLength(50);
// Table & Column Mappings
this.ToTable("UserProfile");
this.Property(t => t.UserId).HasColumnName("UserId");
this.Property(t => t.Email).HasColumnName("Email");
this.Property(t => t.UserName).HasColumnName("UserName");
this.Property(t => t.UserType).HasColumnName("UserType");
this.HasOptional(e => e.UserType1).WithRequired();
The model mapping data for usertypes looks like this:
public class UserType1 : EntityTypeConfiguration<UserType1>
{
public UserType1Map()
{
// Primary Key
this.HasKey(t => t.UserId);
// Properties
this.Property(t => t.UserId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
this.HasRequired(t => t.UserProfile).WithOptional();
this.Property(t => t.Company)
.IsRequired()
.HasMaxLength(50);
// Table & Column Mappings
this.ToTable("UserType1");
this.Property(t => t.UserId).HasColumnName("UserId");
this.Property(t => t.Company).HasColumnName("Company");
// Relationships
this.HasRequired(t => t.UserProfile).WithOptional();
}
}
But I always get this error Unable to determine the principal end of an association between the types 'myApp.Models.UserType1' and 'myApp.Models.UserProfile'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
what did I miss?
Configure the relationship for only one entity (in your case, in UserProfileMap). Explicitly specify the property in the .WithRequired() call as well. Here's demo code that worked for me:
modelBuilder.Entity<SharedKeyRequired>()
.HasOptional( skr => skr.SharedKeyOptional )
.WithRequired( sko => sko.SharedKeyRequired );
public class SharedKeyRequired
{
public int SharedKeyRequiredId { get; set; }
public virtual SharedKeyOptional SharedKeyOptional { get; set; }
}
public class SharedKeyOptional
{
public int SharedKeyOptionalId { get; set; }
public virtual SharedKeyRequired SharedKeyRequired { get; set; }
}
Moho, I voted your answer as correct but I thought I would put MVC equivalent source here for those that might be confused by the verbage.
Desired end result is using the MVC AccountModel and adding code-first tables which have a foreignkey as their primary keys to extend the UserProfile table with an optional 1 to 1 relationship
Modify your user profile class to add a virtual reference to your new table
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public virtual UserInfo UserInfo { get; set; }
}
create your new table I chose to use Data Notation you could specify this in modelBuilder as
modelBuilder.Entity().HasKey(k => k.UserId);
modelBuilder.Entity().Property(ui => ui.UserId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
public class UserInfo
{
[Key,ForeignKey("UserProfile")] //use above or specify this
public int UserId { get; set; }
public virtual UserProfile UserProfile { get; set; }
public int somevalue { get; set; }
public string name { get; set; }
}
override your OnModelCreating member of your context class and specify the relationship as Moho stated
public class UsersContext : DbContext
{
public UsersContext()
: base("DefaultConnection")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// modelBuilder.Entity<UserInfo>().HasKey(k => k.UserId);
// modelBuilder.Entity<UserInfo>().Property(ui => ui.UserId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
modelBuilder.Entity<UserProfile>().HasOptional(ui => ui.UserInfo).WithRequired(up => up.UserProfile);
base.OnModelCreating(modelBuilder);
}
public DbSet<UserProfile> UserProfiles { get; set; }
public DbSet<UserInfo> UserInfoes { get; set; }
}

MVC4 Code first approach, how to fix the following?

I am getting the following error
One or more validation errors were detected during model generation:
\tSystem.Data.Entity.Edm.EdmAssociationEnd: : Multiplicity is not valid in Role 'UserRoles_Roles_Source' in relationship 'UserRoles_Roles'. Because the Dependent Role refers to the key properties, the upper bound of the multiplicity of the Dependent Role must be '1'.
My entities and the associated mappings are defined as follows,
public class UserProfile
{
public UserProfile()
{
UserUserRoles = new List<UserRoles>();
}
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public virtual ICollection<UserRoles> UserUserRoles { get; set; }
}
public class Roles
{
public Roles()
{
RoleUserRoles = new List<UserRoles>();
}
public int RoleId { get; set; }
public string RoleName { get; set; }
public virtual ICollection<UserRoles> RoleUserRoles { get; set; }
}
public class UserRoles
{
public int UserId { get; set; }
public int RoleId { get; set; }
public virtual UserProfile User { get; set; }
public virtual Roles Roles { get; set; }
}
//Mappings
public UserProfileMap()
{
// Primary Key
HasKey(t => t.UserId);
// Properties
Property(t => t.UserName)
.HasMaxLength(56);
// Table & Column Mappings
ToTable("UserProfile");
Property(t => t.UserId).HasColumnName("UserId");
Property(t => t.UserName).HasColumnName("UserName");
}
public class RolesMap : EntityTypeConfiguration<Roles>
{
public RolesMap()
{
// Primary Key
HasKey(t => t.RoleId);
// Properties
Property(t => t.RoleName)
.HasMaxLength(256);
// Table & Column Mappings
ToTable("webpages_Roles");
Property(t => t.RoleId).HasColumnName("RoleId");
Property(t => t.RoleName).HasColumnName("RoleName");
}
}
public class UserRolesMap : EntityTypeConfiguration<UserRoles>
{
public UserRolesMap()
{
// Primary Key
HasKey(t => t.UserId);
HasKey(t => t.RoleId);
// Table & Column Mappings
ToTable("webpages_UsersInRoles");
Property(t => t.UserId).HasColumnName("UserId");
Property(t => t.RoleId).HasColumnName("RoleId");
// Relationships
HasRequired(t => t.User)
.WithMany(t => t.UserUserRoles)
.HasForeignKey(d => d.UserId);
HasRequired(t => t.Roles)
.WithMany(t => t.RoleUserRoles)
.HasForeignKey(d => d.RoleId);
}
}
what am I doing wrong?
Per the comments:
A combined primary key should be constructed as HasKey(t => new { t.UserId, t.RoleId });
It looks like you want to create a many-to-many relation between models. In that case you do not need the class UserRoles, it will be generated by EF when using this scenario:
public class User
{
// other properties
public virtual IList<Role> Roles {get;set;}
}
public class Role
{
// other properties
public virtual IList<User> Users {get;set;}
}
However, if you do want the UserRoles model to for instance store additional information you need to make the mapping manually in for example the OnModelCreating() function of the DbContext class.

Different schema name on correlation table - Entity Framework

Is it possible to have a different schema name on correlation tabels than [dbo]?
I'm using code first.
Example:
ApplicationRole.cs
public class ApplicationRole
{
public Guid ApplicationRoleId { get; set; }
public string Name { get; set; }
public virtual ICollection<ADGroup> ADGroups { get; set; }
}
ADGroup.cs
public class ADGroup
{
public Guid ADGroupId { get; set; }
public string Name { get; set; }
public virtual ICollection<ApplicationRole> ApplicationRoles { get; set; }
}
ApplicationRoleConfiguration.cs
public class ApplicationRoleConfiguration : EntityTypeConfiguration<ApplicationRole>
{
public ApplicationRoleConfiguration()
{
ToTable("T_ApplicationRoles", "LabConfig");
this.HasKey(a => a.ApplicationRoleId);
this.Property(t => t.ApplicationRoleId)
.HasColumnName("ApplicationRole_GUID")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
ADGroupConfiguration.cs
public class ADGroupConfiguration : EntityTypeConfiguration<ADGroup>
{
public ADGroupConfiguration()
{
ToTable("T_ADGroups", "LabConfig");
this.HasKey(a => a.ADGroupId);
this.Property(t => t.ADGroupId)
.HasColumnName("ADGroup_GUID")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
// correlation table should also get schema [LabConfig]
this.HasMany(o => o.ApplicationRoles)
.WithMany(r => r.ADGroups)
.Map(m =>
{
m.MapLeftKey("ADGroup_GUID");
m.MapRightKey("ApplicationRole_GUID");
ToTable("T_ApplicationRoleADGroups", "LabConfig");
});
}
}
But the result on the database is always:
[LabConfig].[T_ADGroups]
[LabConfig].[T_ApplicationRoles]
[dbo].[ApplicationRoleADGroups]
Any ideas? I spent hours for this to work with my desired schema without any success.
In my case i did something stupid i didn't see...
Compare the original ADGroupConfiguration.cs with this:
public class ADGroupConfiguration : EntityTypeConfiguration<ADGroup>
{
public ADGroupConfiguration()
{
ToTable("T_ADGroups", "LabConfig");
this.HasKey(a => a.ADGroupId);
this.Property(a => a.ADGroupId)
.HasColumnName("ADGroup_GUID")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.Property(t => t.Name).HasColumnName("Name").IsRequired();
// the Mapping was causing the error.
// this Mapping is correct now
this.HasMany(o => o.ApplicationRoles)
.WithMany(r => r.ADGroups)
.Map(m => m.MapLeftKey("ADGroup_GUID")
.MapRightKey("ApplicationRole_GUID")
.ToTable("T_ApplicationRoleADGroups", "LabConfig"));
}
}
Hence my mapping had an error it was hiding the real problem i was searching for...
Always double check the mappings!