EF 6 Save related entity composite key - entity-framework

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

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.

Why EF doesnt update navigation property

I use Code First EF 5.0 on >Net 4.0 and I has 2 class:
public partial class Kennel
{
public Kennel()
{
this.Brands = new List<Brand>();
this.Dogs = new List<Dog>();
this.Breeds = new List<Breed>();
this.Owners = new List<Person>();
this.Name1 = new KennelName();
this.Name2 = new KennelName();
}
public int ID { get; set; }
public /*DogClub*/int Type { get; set; }
public KennelName Name1 { get; set; }
public KennelName Name2 { get; set; }
public string CertificateNumber { get; set; }
public System.DateTime? AssigmentDate { get; set; }
public string Folder { get; set; }
public string Comment { get; set; }
public int StatusID { get; set; }
public int? FederationID { get; set; }
public int? MainOwnerID { get; set; }
public int? MainBreedID { get; set; }
public virtual ICollection<Brand> Brands { get; set; }
public virtual ICollection<Dog> Dogs { get; set; }
public virtual Breed MainBreed { get; set; }
public virtual Federation Federation { get; set; }
public virtual Status Status { get; set; }
public virtual Person MainOwner { get; set; }
public virtual ICollection<Breed> Breeds { get; set; }
public virtual ICollection<Person> Owners { get; set; }
}
public partial class Breed
{
public Breed()
{
this.Dogs = new List<Dog>();
this.ExpertKerungs = new List<ExpertKerung>();
this.Hallmarks = new List<Hallmark>();
this.Colors = new List<Color>();
this.ExpertBreeds = new List<ExpertBreed>();
this.Kennels = new List<Kennel>();
this.MainKennels = new List<Kennel>();
}
public int ID { get; set; }
public string FciNumber { get; set; }
public string Name { get; set; }
public int BreedGroupID { get; set; }
public bool IsKerung { get; set; }
public string NameLat { get; set; }
public string NativeName { get; set; }
public int CountryID { get; set; }
public System.DateTime? StandardDate { get; set; }
public bool IsCACIB { get; set; }
public bool IsWork { get; set; }
public virtual BreedGroup BreedGroup { get; set; }
public virtual ICollection<Dog> Dogs { get; set; }
public virtual ICollection<ExpertKerung> ExpertKerungs { get; set; }
public virtual ICollection<Hallmark> Hallmarks { get; set; }
public virtual ICollection<Color> Colors { get; set; }
public virtual Country Country { get; set; }
public virtual ICollection<ExpertBreed> ExpertBreeds { get; set; }
public virtual ICollection<Kennel> Kennels { get; set; }
public virtual ICollection<Kennel> MainKennels { get; set; }
}
and mapping:
public class KennelMap : EntityTypeConfiguration<Kennel>
{
public KennelMap()
{
// Primary Key
this.HasKey(t => t.ID);
// Properties
//this.Property(t => t.Name1.Name)
// .IsRequired();
//this.Property(t => t.Name1.IntlName)
// .IsRequired();
//this.Property(t => t.Name2.Name)
// .IsRequired();
//this.Property(t => t.Name2.IntlName)
// .IsRequired();
// Table & Column Mappings
this.ToTable("Kennels");
this.Property(t => t.ID).HasColumnName("ID");
this.Property(t => t.Type).HasColumnName("Type");
this.Property(t => t.Name1.Name).HasColumnName("Name1_Name");
this.Property(t => t.Name1.IntlName).HasColumnName("Name1_IntlName");
this.Property(t => t.Name1.Type).HasColumnName("Name1_Type");
this.Property(t => t.Name1.Approved).HasColumnName("Name1_Approved");
this.Property(t => t.Name2.Name).HasColumnName("Name2_Name");
this.Property(t => t.Name2.IntlName).HasColumnName("Name2_IntlName");
this.Property(t => t.Name2.Type).HasColumnName("Name2_Type");
this.Property(t => t.Name2.Approved).HasColumnName("Name2_Approved");
this.Property(t => t.CertificateNumber).HasColumnName("CertificateNumber");
this.Property(t => t.AssigmentDate).HasColumnName("AssigmentDate");
this.Property(t => t.Folder).HasColumnName("Folder");
this.Property(t => t.Comment).HasColumnName("Comment");
this.Property(t => t.StatusID).HasColumnName("StatusID");
this.Property(t => t.FederationID).HasColumnName("FederationID");
this.Property(t => t.MainOwnerID).HasColumnName("MainOwnerID");
// Relationships
this.HasMany(t => t.Owners)
.WithMany(t => t.Kennels)
.Map(m =>
{
m.ToTable("OwnerKennel");
m.MapLeftKey("Kennels_ID");
m.MapRightKey("Owners_ID");
});
this.HasOptional(t => t.MainBreed)
.WithMany(t => t.MainKennels)
.HasForeignKey(d => d.MainBreedID);
this.HasOptional(t => t.Federation)
.WithMany(t => t.Kennels)
.HasForeignKey(d => d.FederationID);
this.HasRequired(t => t.Status)
.WithMany(t => t.Kennels)
.HasForeignKey(d => d.StatusID);
this.HasOptional(t => t.MainOwner)
.WithMany(t => t.MainKennels)
.HasForeignKey(d => d.MainOwnerID)
.WillCascadeOnDelete(false);
}
}
If I write next code:
int breedID = 1; // some value
Breed br = _kennel.Breeds.FirstOrDefault(t => t.ID == breedID);
if (br != null)
{
_kennel.MainBreed = br;
// but: _kennel.MainBreedID != br.ID
}
OR:
int breedID = 1; // some value
Breed br = _kennel.Breeds.FirstOrDefault(t => t.ID == breedID);
if (br != null)
{
_kennel.MainBreedID = breedID;
// but: _kennel.MainBreed != br
}
Why EF doesnt update navigation property? I set ProxyCreationEnabled and AutoDetectChangesEnabled, but this not work.
See another example of sample code (it accurately reflects my real application code):
Kennel kennel = ctx.Kennels.Add(ctx.Kennels.Create());
kennel.Name1.Name = "Test Kennel";
List<Breed> breeds = ctx.Breeds.Include(b => b.BreedGroup).OrderBy(t => t.BreedGroupID).Where(t => t.ID == 755 || t.ID == 772).ToList();
foreach (var b in breeds)
kennel.Breeds.Add(b);
if (breeds.Count > 0)
{
kennel.MainBreed = breeds[0];
foreach (var k in kennel.MainBreed.MainKennels)
System.Diagnostics.Debug.WriteLine("MainKennel: " + k.Name1.Name);
ctx.ChangeTracker.DetectChanges();
//System.Diagnostics.Debug.WriteLine("MainBreed: " + kennel.MainBreed);
System.Diagnostics.Debug.WriteLine("MainBreedID: " + kennel.MainBreedID);
}
After call to DetectChanges all navigation properties and collection reflect changes (kennel.MainBreedID != null).
Try making all your POCO properties virtual rather than just the navigation properties. This will allow EF to create change tracking proxies rather than lazy loading proxies. I've not tested this, but you may then get the behavior that you expect.
Remove the intialisation of the collections from the constructor
//this.Dogs = new List<Dog>();
//this.ExpertKerungs = new List<ExpertKerung>();
//this.Hallmarks = new List<Hallmark>();
//this.Colors = new List<Color>();
//this.ExpertBreeds = new List<ExpertBreed>();
//this.Kennels = new List<Kennel>();
//this.MainKennels = new List<Kennel>();

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.