h__
h__

Reputation: 793

Unable to determine the principal end of OR “Value cannot be null, parameter name 'key'”

I have tried almost everything from StackOverflow to prevent these errors. I have no idea what am I doing wrong. When I'm starting with some changes to remove one bug, the second appear and vice versa. I don't know if it connects to DB, or can it initialize DB, or cannot. It looks like my DB file is empty - I'm using SQLite and I want to use Code First mechanism of EF.

My code

using System.Data.Entity;
using ControlCenter;

namespace ControlCenter
{
    public class IncomingMessaggesContext: DbContext
    {
        public DbSet<UnifiedPositionMessage> UnifiedPositionMessages { get; set; }
        public DbSet<MessageDescription> MessageDescriptions { get; set; }

        static IncomingMessaggesContext()
        {
            Database.SetInitializer<IncomingMessaggesContext>(null);
        }
    }
}


using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace ControlCenter.CommunicationGateway
{
    using System;
    using TrackingDevices.Positioning;

     public class UnifiedPositionMessage
     {   

         public int Id { get; set; }

         public uint DeviceID { get; set; }
         public DateTime ReceiveTime { get; set; }
         public PositionBase DevicePosition { get; set; }
         public object UserPayload { get; set; }

         public int MessageDescriptionId { get; set; }

        [ForeignKey("Id")]
        [Required]
        public virtual MessageDescription MessageDescription { get; set; }

     }

     public class MessageDescription
     {
         public int Id { get; set; }
         public bool IsMessageValid { get; set; }

         public virtual UnifiedPositionMessage UnifiedPositionMessage { get; set; }
     }
}

Calling DB

using (var db = new IncomingMessaggesContext()  )
{
    var msgDesc = new MessageDescription() {IsMessageValid = true, Id = 0, UnifiedPositionMessage = e.Frame};
    db.MessageDescriptions.Add(msgDesc);
    db.UnifiedPositionMessages.Add(e.Frame);
    db.SaveChanges();
}

And connection settings

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <entityFramework>
    <connectionStrings>
      <add name="IncomingMessaggesContext"
       connectionString="Data Source=c:\temp\Messages.db;"
       providerName="System.Data.SQLite" />
    </connectionStrings>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
  </entityFramework>
  <system.data>
    <DbProviderFactories>
      <add name="SQLite Data Provider"
            invariant="System.Data.SQLite"
            description="Data Provider for SQLite"
            type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" />
    </DbProviderFactories>
  </system.data>
</configuration>

Upvotes: 1

Views: 381

Answers (3)

h__
h__

Reputation: 793

This is not a struct! public PositionBase DevicePosition { get; set; }. Changing it according to rules from:

  public class PositionBase
  {
    public DateTime GPSTime { get; set; }
    public double Latitude { get; set; }
    public double Longitude { get; set; }
    public float Speed { get; set; }    // [km/h]
    public float Course { get; set; }   // [°]
}

to

public class PositionBase
{
    public int Id { get; set; }
    public DateTime GPSTime { get; set; }
    public double Latitude { get; set; }
    public double Longitude { get; set; }
    public float Speed { get; set; }    // [km/h]
    public float Course { get; set; }   // [°]

    [ForeignKey("Id")]
    [Required]
    public virtual UnifiedPositionMessage UnifiedPositionMessage { get; set; }
}

and adding it to DbContext solves the problem.

public DbSet<PositionBase> PositionBases { get; set; }

Second challenge is that EF doesn't support object types, so it also can cause problems!

Upvotes: 0

Gert Arnold
Gert Arnold

Reputation: 109185

You're defining a 1 (MessageDescription) : 0..1 (UnifiedPositionMessage) association here.

What EF wants to do is define a primary key in one table that at the same time is a foreign key to the other table. In your case, UnifiedPositionMessage would have an non-autoincrementing Id field that points to MessageDescription.Id, which is an auto-incrementing identity column. So any UnifiedPositionMessage record can only exist if its MessageDescription exists. This is enforced by the [Required] attribute.

In this scenario it is no use to have explicit foreign key fields in your entities: there's only one FK that's also a PK, so you will never be able to set it.

So you can remove MessageDescriptionId from your model and, second, tell EF how to map your entities:

modelBuilder.Entity<UnifiedPositionMessage>()
            .HasRequired(u => u.MessageDescription)
            .WithOptional(md => md.UnifiedPositionMessage);

(this is in the DbContext.OnModelCreating override)

Upvotes: 1

Art713
Art713

Reputation: 494

That is probably because Id can't be 0!

var msgDesc = new MessageDescription() {IsMessageValid = true, Id = 0, UnifiedPositionMessage = e.Frame};

You can set your msgDesc as

var msgDesc = new MessageDescription {IsMessageValid = true, UnifiedPositionMessage = e.Frame};

So your records in the db all will have unique Id's.

Upvotes: 0

Related Questions