Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity framework 4.3 with required association

I'm a very strange behavior with EF code first approach and associations. I have two entities:

public class GlobalKpiSectionn
{
    public GlobalKpiSection()
    {
        this.Regions = new HashSet<Region>();
    }

    public virtual ICollection<Region> Regions { get; protected set; }  
}

public class Region
{
    public int RegionId { get; set; }

    public bool IsMain { get; set; }

    [Required]
    public virtual GlobalKpiSection KpiSection { get; set; }
}

I need required attribute on KiSection property in order to get cascade deletes.

The problem is the following - in this code:

var mainRegion = context.Regions.Single(x => x.RegionId == id);
mainRegion.IsMain = true;
context.SaveChanges();

I'm getting exception that Required field is not initialized. But it is present just not loaded. I don't what to write everywhere explicit includes for properties when I use this entity. What can I do to overcome this? Exceptoin details

UPDATE

The reason why I'm sure its lazy loading issue is that:

        var primaryRegion = context.Regions
                                   .Include(x => x.KpiSection)
                                   .Single(x => x.RegionId == id);

Solves the issue, but its definitely awful solution.

like image 558
Sly Avatar asked Feb 16 '12 11:02

Sly


2 Answers

That is why you should not use data annotations. Data annotations are wrong feature because they do both mapping and validation (violation of single responsibility) - as you see it is not always what you want. So your current options are:

  • Turn off validation in context.Configuration.ValidateOnSaveEnabled = false
  • Expose non nullable KpiSectionId foreign key property in your Region entity (you will not need Required attribute on your navigation property).
  • Use fluent API instead of data annotations :

Example:

modelBuilder.Entity<GlobalKpiSection>()
            .WithMany(s => s.Regions)
            .HasRequired(r => r.KpiSection);
like image 57
Ladislav Mrnka Avatar answered Sep 28 '22 15:09

Ladislav Mrnka


To force cascade deletes, you have to use the fluent configurations. You can then remove the [Required]attribute from the KpiSection property.

Something like this:

public class GlobalKpiSectionn
{
    public GlobalKpiSection()
    {
        this.Regions = new HashSet<Region>();
    }

    public virtual ICollection<Region> Regions { get; protected set; }  
}

public class Region
{
    public int RegionId { get; set; }

    public bool IsMain { get; set; }

    public int GlobalKpiSectionId { get; set; }
    public virtual GlobalKpiSection KpiSection { get; set; }
}

public class RegionConfig : EntityTypeConfiguration<Region>
{
    HasRequired(x => x.KpiSection)
        .WithMany(x => x.Regions)
        .HasForeignKey(x => x.GlobalKpiSectionId)
        .WillCascadeOnDelete(true);
}

public class YourContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new RegionConfig());
    }
}
like image 43
Kristof Claes Avatar answered Sep 28 '22 16:09

Kristof Claes