2

I have the following entities:

public abstract class Meter
{
    public int MeterId { get; set; }
    public string EANNumber { get; set; }
    public string MeterNumber { get; set; }
    [Required]
    public virtual Premise Premise { get; set; }
    public abstract void AddReading(CounterReading reading);
}

public class GasMeter : Meter
{
    public virtual Counter Counter { get; private set; }

    public override void AddReading(CounterReading reading)
    {
        Counter.Readings.Add(reading);
    }
}

public class Premise
{
    [Key]
    public int PremiseId { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }

    [Required]
    public virtual Address Address { get; set; }
    public string Type { get; set; }

    public virtual GasMeter GasMeter { get; set; }
}

I have a 1:1 relation between a GasMeter and a Premise.

What must I do so that I can set myPremise.GasMeter = myMeter, and retrieve myPremise in later code with myMeter.Premise?

Edit When setting it up via the Fluent API as follows:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Premise>().HasOptional(p => p.GasMeter)
            .WithRequired(m => m.Premise);
    }

I get the following exception when running:

An exception of type 'System.Data.Entity.ModelConfiguration.ModelValidationException' occurred in EntityFramework.dll but was not handled in user code

Additional information: One or more validation errors were detected during model generation:

Premise: FromRole: NavigationProperty 'Premise' is not valid. Type 'GasMeter' of FromRole 'Premise_GasMeter_Target' in AssociationType 'Premise_GasMeter' must exactly match with the type 'Meter' on which this NavigationProperty is declared on.

Does this mean that I can't use Navigation Properties with inheritance? How would I solve my problem then?

Benjamin Diele
  • 1,177
  • 1
  • 10
  • 26
  • See this: http://stackoverflow.com/a/27727545/861716 – Gert Arnold Jan 24 '15 at 21:56
  • 1
    Either `public virtual Premise Premise { get; set; }` should be in `GasMeter` or `public virtual GasMeter GasMeter` should be `public virtual Meter Meter`. – Gert Arnold Jan 25 '15 at 09:03
  • @GertArnold Yes, I put the Premise in my GasMeter. I have multiple Meters on my Premise (GasMeter, WaterMeter, ElectricityMeter) and would like to keep the type safety there. – Benjamin Diele Jan 25 '15 at 10:12
  • @GertArnold Putting the `Premise` property on my Meter makes my MeterId wrong. EF doesn't auto-increment the MeterId anymore then. – Benjamin Diele Jan 25 '15 at 19:19
  • No, `Premise` is the principle entity, `Meter` only copies `Premise`'s PK value, it doesn't generate its own. So both always have the same PK (and `Meter`'s PK is also an FK to `Premise`). That's how it works with 1:1. – Gert Arnold Jan 25 '15 at 19:41
  • @GertArnold Then I think I'm wrong, because besides my `GasMeter`, I also have a Water- and ElectricityMeter on my Premise. – Benjamin Diele Jan 25 '15 at 20:00

2 Answers2

0

I think you need to add the Id to each class for PK/FK relationship

public abstract class Meter
{
   ....
    public int PremiseId
    public virtual Premise Premise { get; set; }
}

and

public class Premise
{
   ....
   public int GasMeterId
   public virtual GasMeter GasMeter{ get; set; }
}
SWilko
  • 3,542
  • 1
  • 16
  • 26
0

You probably don't need to link these two entities as virtual properties within each other. Try modify Meter class to keep the PremiseId since it is the primary key of Premise table then get the Premise entity using Select(x => x.PremiseId == aMeter.PremiseId).SingleOrDefault() to get the Premise mapped to this GasMeter

public abstract class Meter
{
    public int MeterId { get; set; }
    public string EANNumber { get; set; }
    public string MeterNumber { get; set; }
    public int PremiseId { get; set; }
    public abstract void AddReading(CounterReading reading);
}

SET

var aPremise = new Premise();
var aMeter = new GasMeter();
aPremise.GasMeter = aMeter;
aMeter.PremiseId = aPremise.PremiseId;

GET

var thePremise = _repository.Set<Premise>.Select(x => x.PremiseId == aMeter.PremiseId).SingleOrDefault();
display name
  • 4,165
  • 2
  • 27
  • 52