Mapping relationships that require a navigation property only on one side - entity-framework

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.

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.

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!

Entity Framework TPH Inheritance errors:

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.

Foreign Key with Fluent Entity Framework

I have created a News Model. My News have an author which is of the Member Class.
is this enough for the foreing key to be set?
HasRequired(n => n.Author);
Code:
public class Member : Identity
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public Address Address { get; set; }
public int Id { get; set; }
public virtual ICollection<News> News { get; set; }
}
public class News
{
public string Title { get; set; }
public string Subtile { get; set; }
public int Id { get; set; }
public string Url { get; set; }
public DateTime DateAdded { get; set; }
public virtual Member Author;
}
public class NewsMap : EntityTypeConfiguration<News>
{
public NewsMap()
{
HasKey(n => n.Id);
Property(n => n.Id).
HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
.HasColumnName("Id");
Property(t => t.Title)
.IsRequired()
.HasMaxLength(100)
.IsUnicode();
Property(t => t.Subtile)
.IsRequired()
.HasMaxLength(100)
.IsUnicode();
Property(t => t.Url)
.IsRequired()
.HasMaxLength(255)
.IsUnicode();
Property(t => t.DateAdded).HasColumnName("DateAdded")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
HasRequired(n => n.Author); //is this enough for the foreing key to be set?
}
}
public class MemberMap : EntityTypeConfiguration<Member>
{
public MemberMap()
{
// Primary Key
this.HasKey(t => t.Id);
// Properties
this.Property(t => t.FirstName)
.IsRequired()
.HasMaxLength(150);
this.Property(t => t.LastName)
.IsRequired()
.HasMaxLength(50);
this.Property(t => t.Email)
.IsRequired()
.HasMaxLength(150);
this.Property(t => t.Address.Id)
.IsRequired()
.HasMaxLength(100)
.HasColumnName("Address_FirstLine");
this.Property(t => t.Address.ZipCode)
.IsRequired()
.HasMaxLength(20).HasColumnName("Address_Zip");
this.Property(t => t.Address.Contry)
.IsRequired()
.HasMaxLength(100).HasColumnName("Address_Contry");
this.Property(t => t.Address.City)
.IsRequired()
.HasMaxLength(100).HasColumnName("Address_Town");
this.Property(t => t.Id);
// Table & Column Mappings
this.ToTable("Identities_Member");
this.Property(t => t.FirstName).HasColumnName("FirstName");
this.Property(t => t.LastName).HasColumnName("LastName");
this.Property(t => t.Email).HasColumnName("Email");
this.Property(t => t.Id).HasColumnName("Id");
// Relationships
}
}
Thanks #Gert for the answer:
It is not enough. It is too much. Well, strictly speaking. The FK will even be set (as in generated in the database's data model) without the HasRequired. With it, the FK will be not nullable.