Foreign Key with Fluent Entity Framework - 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.

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.

EF 6 Save related entity composite key

I have the following EF Entities:
public class EmployeeHoliday
{
public int HolidayId { get; set; }
public int EmployeeId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public bool IsActive { get; set; }
}
public class EmployeeHolidayItem
{
public int HolidayId { get; set; }
public DateTime Date { get; set; }
public int EmployeeId { get; set; }
public string MasterEntity { get; set; }
public bool IsRealHoliday { get; set; }
public bool IsActive { get; set; }
}
The EF Configuration Map are:
public EmployeeHolidayMap()
{
// Primary Key
this.HasKey(t => t.HolidayId);
// Properties
this.Property(t => t.HolidayId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
// Properties
this.Property(t => t.EmployeeId)
.IsRequired();
// Table & Column Mappings
this.ToTable("employee_holiday");
this.Property(t => t.HolidayId).HasColumnName("holidayid");
this.Property(t => t.EmployeeId).HasColumnName("employeeid");
this.Property(t => t.StartDate).HasColumnName("startdate");
this.Property(t => t.EndDate).HasColumnName("enddate");
this.Property(t => t.IsActive).HasColumnName("isactive");
}
public EmployeeHolidayItemMap()
{
// Primary Key
this.HasKey(t => new { t.HolidayId, t.Date });
this.Property(t => t.EmployeeId)
.IsRequired();
this.Property(t => t.MasterEntity)
.IsRequired();
// Table & Column Mappings
this.ToTable("employee_holiday_item");
this.Property(t => t.HolidayId).HasColumnName("holidayid");
this.Property(t => t.Date).HasColumnName("date");
this.Property(t => t.EmployeeId).HasColumnName("employeeid");
this.Property(t => t.MasterEntity).HasColumnName("masterentity");
this.Property(t => t.IsRealHoliday).HasColumnName("isrealholiday");
this.Property(t => t.IsActive).HasColumnName("isactive");
}
Now Im trying to Save a new EmployeeHoliday with a few EmployeeHolidayItems but I get an error with the HolidayId key in the EmployeeHolidayItems model.
This is the code for inserting a new EmployeeHoliday:
int holidayId = 0;
var newRequest = new Model.EmployeeHoliday();
newRequest.HolidayId = holidayId;
newRequest.EmployeeId = request.EmployeeId;
newRequest.StartDate = dates.FirstOrDefault();
newRequest.EndDate = dates.LastOrDefault();
newRequest.IsActive = true;
var newRequestDates = new List<Model.EmployeeHolidayItem>();
// Add Days to Holiday Item
foreach (var date in dates)
{
var newDate = new Model.EmployeeHolidayItem();
newDate.HolidayId = holidayId;
newDate.EmployeeId = request.EmployeeId;
newDate.MasterEntity = Uow.MasterEntity;
newDate.Date = date;
newDate.IsRealHoliday = true;
newDate.IsActive = true;
// add to list
newRequestDates.Add(newDate);
}
DbContext.EmployeeHoliday.Add(newRequest);
DbContext.EmployeeHolidayItem.AddRange(newRequestDates);
DbContext.SaveChanges();
Is there a way I can force the relation between EmployeeHoliday and EmployeeHolidayItem when inserting new record? I don't want to make the relation in my Mapping.
Add this property on EmployeeHoliday class.
public class EmployeeHoliday
{
public ICollection<EmployeeHolidayItem> EmployeeHolidayItems {get;set;}
}
And replace this
DbContext.EmployeeHoliday.Add(newRequest);
DbContext.EmployeeHolidayItem.AddRange(newRequestDates);
with
newRequest.EmployeeHolidayItems = newRequestDates;
DbContext.EmployeeHoliday.Add(newRequest);

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.

Code First Entity Framework adds an underscore to a primary key column name

I have a fluent mapping of a domain class that defines the names for each column including the primary key which is made up of two columns, NotificationId and IdentityId. These are also foreign keys that point at Notification.Id and Identity.Id respectively. Whenever I use this mapping as part of a query it generates a sql query with an underscore in between Notification and Id (Notification_Id) that is not mentioned anywhere in my mappings.
I would expect that there might be some convention that says that primary keys or foreign keys should look like that but it seems odd given that I've explicitly told it what the column name for NotificationId is.
Any help would be appreciated.
Added mapping file
public class Notifications_IdentitiesMap : EntityTypeConfiguration<Notifications_Identities>
{
public Notifications_IdentitiesMap()
{
ToTable("Notifications.Notifications_Identities");
HasKey(x => new { x.NotificationId,x.IdentityId });
Property(x => x.IdentityId).HasColumnName("IdentityId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
Property(x => x.NotificationId).HasColumnName("NotificationId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
Property(x => x.SendAttempts).HasColumnName("SendAttempts");
Property(x => x.IsSent).HasColumnName("IsSent");
Property(x => x.LastSendAttempt).HasColumnName("LastSendAttempt");
HasRequired(x => x.Notification).WithMany().HasForeignKey(x => x.NotificationId);
HasRequired(x => x.Identity).WithMany().HasForeignKey(x => x.IdentityId);
}
}
public class Notifications_Identities
{
public Notifications_Identities()
{
}
public Notifications_Identities(Notification notification, int identityId)
{
Notification = notification;
IdentityId = identityId;
}
public virtual int IdentityId { get; set; }
public virtual int NotificationId { get; set; }
public virtual int SendAttempts { get; set; }
public virtual DateTime? LastSendAttempt { get; set; }
public virtual Identities.Identity Identity { get; set; }
public virtual Notification Notification { get; set; }
public bool IsSent { get; set; }
}
public class NotificationMap:EntityTypeConfiguration<Notification>
{
public NotificationMap()
{
ToTable("Notifications.Notifications");
Property(x => x.Id).HasColumnName("Id");
Property(x => x.Subject).HasColumnName("Subject").HasMaxLength(255);
Property(x => x.Message).HasColumnName("Message");
Property(x => x.TypeId).HasColumnName("TypeId");
Property(x => x.DateCreated).HasColumnName("DateCreated");
Property(x => x.CreatorIdentityId).HasColumnName("CreatorIdentityId");
HasRequired(x => x.Creator).WithMany().HasForeignKey(x => x.CreatorIdentityId);
}
}
public class IdentityMap : EntityTypeConfiguration<RM.Domain.Identities.Identity>
{
public IdentityMap()
{
Property(x => x.Id).HasColumnName("IDENTITYID").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(x => x.FirstName).HasColumnName("firstname");
Property(x => x.Surname).HasColumnName("surname");
Property(x => x.Username).HasColumnName("username");
Property(x => x.IsGroup).HasColumnName("is_group");
Property(x => x.EmailAddress).HasColumnName("email");
Property(x => x.ActiveDirectoryId).HasColumnName("ActiveDirectoryId");
Property(x => x.IsLive).HasColumnName("is_active");
ToTable("dbo.rm_tbl_IDENTITY_Identities");
}
}
I made a stupid mistake, found the answer in Entity Framework 4.1 Code First Foreign Key Id's
I added the following:
public virtual ICollection<Notifications_Identities> Identities { get; set; }
to the Notification entity and didn't map it
The fix was to change
HasRequired(x => x.Notification).WithMany().HasForeignKey(x => x.NotificationId);
to
HasRequired(x => x.Notification).WithMany(x=>x.Identities).HasForeignKey(x => x.NotificationId);