Ok I think I may have got this wrong in the model builder. I want the case which can be one case but inside that one case they can be many relationships.
modelBuilder.Entity<RelationShips>()
.HasOne<MISObject>(s => s.Case)
.WithMany(g => g.RelationShip)
.HasForeignKey(s => s.MisObjectId);
But when I attempt to save with the above
DbUpdateException: An error occurred while updating the entries. See
the inner exception for details. SqlException: The INSERT statement
conflicted with the FOREIGN KEY constraint
"FK_RelationShips_MISobject_MisObjectId". The conflict occurred in
database "MISSystem", table "dbo.MISobject", column 'Id'. The
statement has been terminated.
My MISObject has a collection of relationships as such
public class MISObject {
public int Id { get; set; }
public ICollection<RelationShips> RelationShip { get; set; }
}
public class RelationShips {
public int Id { get; set; }
public MISObject Case { get; set; }
}
Will the above not allow a one to many relationship basically one case could have 20 relationships but there could be many cases. But those 20 relationships should only belong to that case if that makes since.
I think I need to use hasmany but not to sure how in this context.
Edit 2
I think this might be what i need but im not sure how legal it is.
modelBuilder.Entity<MISObject>()
.HasMany(c => c.RelationShip);
modelBuilder.Entity<RelationShips>()
.HasMany(c => c.PersonOfIntrests);
modelBuilder.Entity<POI>()
.HasMany(c => c.PersonOfIntrestsPhotos)
.WithOne(e => e.PersonOfIntrest);
To make this work with the FluentAPI, you need to completely define the navigation and use a foreign key:
public class Relationship {
public int Id { get; set; }
public int MisObjectId { get; set; } // <-- add foreign key ID
public MisObject Case { get; set; }
}
public class Context : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MisObject>()
.HasMany(o => o.Relationships)
.WithOne(r => r.Case) // <-- add other endpoint
.HasForeignKey(r => r.MisObjectId); // <-- add FK property
}
}
Here is a fully working console project, that demonstrates these concepts:
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace IssueConsoleTemplate
{
public class MisObject {
public int Id { get; set; }
public ICollection<Relationship> Relationships { get; set; }
}
public class Relationship {
public int Id { get; set; }
public int MisObjectId { get; set; } // <-- add foreign key ID
public MisObject Case { get; set; }
}
public class Context : DbContext
{
public DbSet<MisObject> MisObjects { get; set; }
public DbSet<Relationship> Relationships { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(#"Data Source=.\MSSQL14;Integrated Security=SSPI;Initial Catalog=So62854210")
.UseLoggerFactory(
LoggerFactory.Create(
b => b
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MisObject>()
.HasMany(o => o.Relationships)
.WithOne(r => r.Case) // <-- add other endpoint
.HasForeignKey(r => r.MisObjectId); // <-- add FK property
// Technically not necessary, because this navigation has already been defined
// in the previous line, but might be good practice anyway.
modelBuilder.Entity<Relationship>()
.HasOne(r => r.Case)
.WithMany(o => o.Relationships)
.HasForeignKey(r => r.MisObjectId);
}
}
internal static class Program
{
private static void Main()
{
using (var context = new Context())
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var newMisObject = new MisObject();
var newRelationships = new[]
{
new Relationship {Case = newMisObject},
new Relationship {Case = newMisObject},
new Relationship {Case = newMisObject},
};
context.MisObjects.Add(newMisObject);
context.Relationships.AddRange(newRelationships);
context.SaveChanges();
}
using (var context = new Context())
{
var misObjects = context.MisObjects
.Include(o => o.Relationships)
.ToList();
Debug.Assert(misObjects.Count == 1);
Debug.Assert(misObjects[0].Relationships.Count == 3);
}
}
}
}
Coincidentally, because the properties in this example follow EF Core naming conventions, you could even remove the OnModelCreating() method entirely here and the result would still work.
See Relationships: Conventions for further information on that.
Just use convention there is no need to use fluent config for relationships:
public class MISObject
{
public int Id { get; set; }
public ICollection<RelationShips> RelationShip { get; set; }
}
public class RelationShips
{
public int Id { get; set; }
public int CaseId { get; set; }
public MISObject Case { get; set; }
}
without any error, EF Core makes your Tables in the database.
Related
There is a EF project that is used by an ASP.NET MVC app. The EF project was built on a legacy database (using a database-first approach).
When I try to load child records for a Machine the collection Maschinentagessaetze stays empty, even though there are records in the database with the correct foreign key.
Is there any way to debug this? I have no idea what the problem could be? From what I found on the internet, this should work.
// Controller
Machine = db09.Maschinen
.Include(x => x.Maschinentagessaetze)
.FirstOrDefault(x => x.DMasId == id);
// after this line, Machine.Maschinentagessaetze is empty
var MachineTagessaetzeList = db09.Maschinentagessaetze.Where(x=> x.OMaschineFk == id).ToList();
//after this line, MachineTagessaetzeList is filled with Machine also beeing loaded
//when this line is active, Machine.Maschinentagessaetze is filled
//whitout this line, it stays empty
// Models
[Table("t_Maschinen")]
public partial class TMaschinen
{
public TMaschinen()
{
Maschinentagessaetze = new HashSet<TMaschinentagessaetze>();
}
[Key]
[Column("d_MAS_ID")]
public int DMasId { get; set; }
[Column("o_Bezeichnung")]
public string OBezeichnung { get; set; } = null!;
public virtual ICollection<TMaschinentagessaetze> Maschinentagessaetze { get; set; }
}
[Table("t_Maschinentagessaetze")]
public partial class TMaschinentagessaetze
{
[Key]
[Column("d_MTA_ID")]
public int DMtaId { get; set; }
[Column("o_Maschinentagessatz")]
public decimal OMaschinentagessatz { get; set; }
[Column("o_Maschine_FK")]
public int OMaschineFk { get; set; }
// with [ForeignKey("OMaschineFk")] the problem remains
public TMaschinen TMaschinen { get; set; }
}
// DbContext
using Microsoft.EntityFrameworkCore;
public virtual DbSet<TMaschinen> Maschinen { get; set; } = null!;
public virtual DbSet<TMaschinentagessaetze> Maschinentagessaetze { get; set; } = null!;
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<TMaschinen>()
.HasMany(m => m.Maschinentagessaetze)
.WithOne(t => t.TMaschinen)
.HasForeignKey(m => m.OMaschineFk);
}
// In the database, there is a foreign key constraint on the child table:
ALTER TABLE [dbo].[t_Maschinentagessaetze] WITH CHECK
ADD CONSTRAINT [FK_t_Maschinentagessaetze_t_Maschinen]
FOREIGN KEY([o_Maschine_FK]) REFERENCES [dbo].[t_Maschinen] ([d_MAS_ID])
ON DELETE CASCADE
I consider you should refact OnModelCreating method:
Parent Entity
modelBuilder.Entity<TMaschinen>()
builder.ToTable("TMaschines");
builder.HasKey(i => i.Id);
builder.Property(i => i.Id)
.ValueGeneratedOnAdd();//you decide how to generate id
builder.Property(i => i.OBezeichnung )
.HasMaxLength(150)
.IsRequired();
Child Entity (Add propertites that are missing)
modelBuilder.Entity<TMaschinentagessaetze>()
builder.ToTable("TMaschinentagessaetzes");
builder.HasKey(i => i.Id);
builder.Property(i => i.Id)
.ValueGeneratedOnAdd(); //you decide how to generate id
.HasOne(m => m.TMaschinen )
.WithMany(t => t.Maschinentagessaetze )
.HasForeignKey(m => m.OMaschineFk);
I am very new to Entity Framework Core (Entity Framework in General), and I have watched several tutorial videos and done a Pluralsight course.
I am using ASP.NET Web API, and I want to add a new entity, that has a One-to-Many relationship. The models are as follows:
"Parent" Class:
public partial class VerificationVoltage
{
public int Id { get; set; }
public DateTime Date { get; set; }
public string Type { get; set; }
public int VerificationVoltageSerialId { get; set; }
public VerificationVoltageSerial Serial { get; set; }
}
"Child" Class:
public class VerificationVoltageSerial
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
[MaxLength(20)]
public string Serial { get; set; }
public List<VerificationVoltage> VerificationVoltage { get; set; }
}
I would like the VerificationVoltageSerial.Serial to be unique, and that the database will first check whether or not the serial exists, before adding the newly added serial (The serials themselves are unique).
Is there a way to do the following: If a row with the same serial exist, as what needs to be added, entity framework then automatically selects the Serial and SerialId and populates the Entity that is being added, with the serial selected from the database.
This is what I am doing currently, I feel that this is a very manual check, an maybe there is something more automatic: (i.e I want it to wrok, even if I remove the IF Statement and the exisitngEntry query in the controller)
[HttpPost]
public async Task<VerificationVoltage> AddVerificationVoltage(VerificationVoltage verificationVoltage)
{
var exisitngEntry = await repository.GetBySerialNoTracking(verificationVoltage.Serial.Serial)
.ConfigureAwait(false);
if (exisitngEntry != null)
{
var existingSerial = exisitngEntry.Serial;
verificationVoltage.Serial.Id = existingSerial.Id;
verificationVoltage.Serial = new VerificationVoltageSerial()
{
Id = existingSerial.Id,
Serial = existingSerial.Serial,
};
}
var addedEntry = repository.Add(verificationVoltage);
await repository.SaveChanges().ConfigureAwait(false);
return addedEntry;
}
public async Task<VerificationVoltage> GetBySerialNoTracking(string serialNumber)
{
return await DbSet.Include(a => a.Serial)
.Where(a => a.Serial.Serial.Equals(serialNumber))
.OrderBy(a => a.VerificationVoltageSerialId)
.AsNoTracking()
.FirstOrDefaultAsync()
.ConfigureAwait(false);
}
My protected override void OnModelCreating(ModelBuilder modelBuilder) method, only repeats the attributes:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ValidationLabAmbientMeasurements>()
.HasOne(a => a.AmbientMeasurementsIdentifier)
.WithMany();
modelBuilder.Entity<VerificationVoltage>()
.Property(a => a.Id)
.ValueGeneratedOnAdd();
modelBuilder.Entity<VerificationVoltage>()
.HasOne(a => a.Serial)
.WithMany(nameof(VerificationVoltage));
modelBuilder.Entity<VerificationVoltage>()
.HasMany(a => a.VerificationVoltageMeasurements)
.WithOne(nameof(VerificationVoltage));
}
I have tried searching for answers, but my search queries do not get results on this specific issue.
In the configuration below, EF creates an index on SyntaxId by convention. Since I have a composite primary key (serves as index) and no identity column, I do not think this convention-created index on a single column is needed in a many-to-many table.
How can I prevent this convention index (b.HasIndex("SyntaxId");) from being auto-created?
public class SoftwareSyntaxTypeConfiguration : BaseJunctionTypeConfiguration<SoftwareSyntax>
{
public override void Configure(EntityTypeBuilder<SoftwareSyntax> entityTypeBuilder)
{
base.Configure(entityTypeBuilder);
entityTypeBuilder.ToTable("software_syntaxes");
entityTypeBuilder.HasKey(x => new {x.SoftwareId, x.SyntaxId});
entityTypeBuilder.HasOne(x => x.Software)
.WithMany(x => x.SoftwareSyntaxes)
.HasForeignKey(x => x.SoftwareId);
entityTypeBuilder.HasOne(x => x.Syntax)
.WithMany(x => x.SoftwareSyntaxes)
.HasForeignKey(x => x.SyntaxId);
}
}
partial class FilterListsDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
modelBuilder.Entity("FilterLists.Data.Entities.Junctions.SoftwareSyntax", b =>
{
b.Property<int>("SoftwareId");
b.Property<int>("SyntaxId");
b.HasKey("SoftwareId", "SyntaxId");
b.HasIndex("SyntaxId"); //TODO: prevent this from being auto-created
b.ToTable("software_syntaxes");
});
}
}
Update: Adding entity classes for clarification.
public class Software
{
public int Id { get; set; }
public ICollection<SoftwareSyntax> SoftwareSyntaxes { get; set; }
...
}
public class Syntax
{
public int Id { get; set; }
public ICollection<SoftwareSyntax> SoftwareSyntaxes { get; set; }
...
}
public class SoftwareSyntax
{
public int SoftwareId { get; set; }
public Software Software { get; set; }
public int SyntaxId { get; set; }
public Syntax Syntax { get; set; }
}
As it turns out, this is not officially supported yet.
A workaround, though, is to use an internal EF API. Its use carries the caveat that it could be changed without notice as it is not intended for external use.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
((Model)modelBuilder.Model).ConventionDispatcher.StartBatch();
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
foreach (var index in entityType.GetIndexes().ToList())
// if index is one you want to remove
entityType.RemoveIndex(index.Properties);
}
via Arthur Vickers
Since I have all of my many-to-many entities in the same Junctions namespace, the implementation that works for me currently is:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
((Model)modelBuilder.Model).ConventionDispatcher.StartBatch();
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
foreach (var index in entityType.GetIndexes().ToList())
if (index.DeclaringEntityType.Name.Contains("Junctions"))
entityType.RemoveIndex(index.Properties);
}
I have introduced a many to many relationship between two of my existing tables. For this, I have added a third table, which contains only the Ids of the other two tables.
Since I am using EF, I have also added
public virtual List<EntityOne> EntityOnes in EntityTwo
and
public virtual List<EntityTwo> EntityTwos in EntityOne.
However, with this, when I get the EntityTwo object, it does not contain the associated EntityOne object. The list has a count of zero, even though the data is there in the tables.
Am I missing something here? Is there anything else, I need to do?
Not sure,if this is relevant, but I have also this in OnModelCreation
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<EntityOne>().
HasMany(p => p.EntityTwos).
WithMany(a => a.EntityOnes).
Map(
m =>
{
m.MapLeftKey("EntityTwoId");
m.MapRightKey("EntityOneId");
m.ToTable("EntityRelations");
});
////Make sure a context is not created by default.
}
Try this:
public partial class One
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public virtual int Id { get; set; }
private ICollection<OneTwo> _oneTwos;
public virtual ICollection<OneTwo> OneTwos
{
get { return _oneTwos ?? (_oneTwos = new List<OneTwo>()); }
set { _oneTwos = value; }
}
}
public partial class Two
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public virtual int Id { get; set; }
private ICollection<OneTwo> _oneTwos;
public virtual ICollection<OneTwo> OneTwos
{
get { return _oneTwos ?? (_oneTwos = new List<OneTwo>()); }
set { _oneTwos = value; }
}
}
Add navigation properties to the join class:
public partial class OneTwo
{
public virtual int OneId { get; set; }
public virtual int TwoId { get; set; }
public virtual One One { get; set; }
public virtual Two Two { get; set; }
}
Add composite key to the join class and configure relationships:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<OneTwo>() // composite primary key
.HasKey(p => new { p.OneId, p.TwoId });
modelBuilder.Entity<OneTwo>()
.HasRequired(a => a.One)
.WithMany(c => c.OneTwos)
.HasForeignKey(fk => fk.OneId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<OneTwo>()
.HasRequired(a => a.Two)
.WithMany(c => c.OneTwos)
.HasForeignKey(fk => fk.TwoId)
.WillCascadeOnDelete(false);
// TODO: handle orphans when last asociation is deleted
}
An alternative strategy is to configure EF relationships via EntityTypeConfiguration<>. The following many-to-many relationship implementation demonstrates that approach:
City.cs
public partial class City
{
public virtual int Id { get; set; }
private ICollection<CountyCity> _countiesCities;
public virtual ICollection<CountyCity> CountiesCities
{
get { return _countiesCities ?? (_countiesCities = new List<CountyCity>()); }
set { _countiesCities = value; }
}
}
County.cs
public partial class County
{
public virtual int Id { get; set; }
private ICollection<CountyCity> _countiesCities;
public virtual ICollection<CountyCity> CountiesCities
{
get { return _countiesCities ?? (_countiesCities = new List<CountyCity>()); }
set { _countiesCities = value; }
}
}
CountyCity.cs
public partial class CountyCity
{
public virtual int CountyId { get; set; }
public virtual int CityId { get; set; }
public virtual County County { get; set; }
public virtual City City { get; set; }
}
CountyCityConfiguration.cs (EF 6 implementation)
public class CountyCityConfiguration : IEntityTypeConfiguration<CountyCity>
{
public void Map(EntityTypeBuilder<CountyCity> builder)
{
// Table and Schema Name declarations are optional
//ToTable("CountyCity", "dbo");
// composite primary key
builder.HasKey(p => new { p.CountyId, p.CityId });
builder.HasOne(pt => pt.County)
.WithMany(p => p.CountiesCities)
.HasForeignKey(pt => pt.CountyId)
.OnDelete(DeleteBehavior.Restrict);
builder.HasOne(pt => pt.City)
.WithMany(t => t.CountiesCities)
.HasForeignKey(pt => pt.CityId)
.OnDelete(DeleteBehavior.Restrict);
// TODO: handle orphans when last association is deleted
}
}
Entity Framework 6 Implementations:
You may configure the composite key and relationships using EntityTypeConfiguration<> as the previous code demonstrates.
Entity Framework Core Implementations:
EntityTypeConfiguration<> has not yet been migrated. However, it is on the roadmap for the next release.
In the meantime, you can employ the temporary pattern suggested by the EF team, or one of the patterns discussed this rather lengthy StackOverflow post discussing entity configuration in Entity Framework 7.
I implemented the pattern posted by Cocowalla in the lengthy discussion prior to reading the EF Team post. The source code for my workaround is available in this GitHub repository.
IEntityTypeConfiguration.cs
namespace Dna.NetCore.Core.DAL.EFCore.Configuration.Temporary.Cocowalla
{
// attribute: https://stackoverflow.com/questions/26957519/ef-7-mapping-entitytypeconfiguration/35373237#35373237
public interface IEntityTypeConfiguration<TEntityType> where TEntityType : class
{
void Map(EntityTypeBuilder<TEntityType> builder);
}
}
Here is my implementation of that pattern:
namespace Dna.NetCore.Core.DAL.EFCore.Configuration.Common
{
public class StateOrProvinceConfiguration : IEntityTypeConfiguration<StateOrProvince>
{
public void Map(EntityTypeBuilder<StateOrProvince> builder)
{
// EF Core
builder.HasOne(p => p.Country).WithMany(p => p.StateOrProvinces).HasForeignKey(s => s.CountryId).OnDelete(DeleteBehavior.Cascade);
builder.HasMany(d => d.Cities).WithOne().OnDelete(DeleteBehavior.Cascade);
builder.HasMany(d => d.Counties).WithOne().OnDelete(DeleteBehavior.Cascade);
}
}
}
I am using Entity Framework 4.3.1 against a SQL Server 2012 database and I am using the POCO approach. I am getting the following error and I am wondering if anyone can explain how to fix it:
ModelValidationException
One or more validation errors were detected during model generation:
\tSystem.Data.Entity.Edm.EdmAssociationConstraint: : The number of properties in the Dependent and Principal Roles in a relationship constraint must be identical.
There is no InnerException available for any further information.
I cannot change the database schema and it is a little odd, but here it is...
** are the primary key (notice I have composite primary keys)
(FK) Denotes a foreign key
Here are the tables (if it helps I can post the SQL to generate them but I do not think the tables are actually the problem as the exception is in the validation of the model):
One
-
**OneId int not null
**TwoId int not null (FK)
**ThreeId int not null (FK)
Name nvarchar(50) not null
Two
-
**TwoId int not null
**ThreeId int not null (FK)
Name nvarchar(50) not null
Three
-
**ThreeId not null
Name nvarchar(50) not null
Here are the entities (notice that I am including the foreign keys in the model but other than that pretty standard):
public class Three
{
public int ThreeId { get; set; }
public string Name { get; set; }
public virtual ICollection<Two> Twos { get; private set; }
public virtual ICollection<One> Ones { get; private set; }
public void AddOne(One one)
{
if (one == null)
throw new ArgumentNullException("two");
if (Ones == null)
Ones = new List<One>();
if (!Ones.Contains(one))
Ones.Add(one);
one.Three = this;
}
public void AddTwo(Two two)
{
if (two == null)
throw new ArgumentNullException("two");
if (Twos == null)
Twos = new List<Two>();
if (!Twos.Contains(two))
Twos.Add(two);
two.Three = this;
}
}
public class Two
{
public int TwoId { get; set; }
public int ThreeId { get; set; }
public string Name { get; set; }
public virtual Three Three { get; set; }
public virtual ICollection<One> Ones { get; private set; }
public void AddOne(One one)
{
if (one == null)
throw new ArgumentNullException("two");
if (Ones == null)
Ones = new List<One>();
if (!Ones.Contains(one))
Ones.Add(one);
one.Two = this;
}
}
public class One
{
public int OneId { get; set; }
public int TwoId { get; set; }
public int ThreeId { get; set; }
public virtual Two Two { get; set; }
public virtual Three Three { get; set; }
}
And here is the data context:
public class DbCtx : DbContext
{
public DbCtx(string connectionString)
: base(connectionString)
{
Ones = Set<One>();
Twos = Set<Two>();
Threes = Set<Three>();
}
public DbSet<One> Ones { get; private set; }
public DbSet<Two> Twos { get; private set; }
public DbSet<Three> Threes { get; private set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var one = modelBuilder.Entity<One>();
one.ToTable("One");
one.HasKey(d => new
{
d.OneId,
d.TwoId,
d.ThreeId
});
one.Property(d => d.OneId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
one.HasRequired(t => t.Two)
.WithMany(s => s.Ones)
.HasForeignKey(t => t.TwoId);
one.HasRequired(t => t.Three)
.WithMany(s => s.Ones)
.HasForeignKey(t => t.ThreeId);
var two = modelBuilder.Entity<Two>();
two.ToTable("Two");
two.HasKey(d => new
{
d.TwoId,
d.ThreeId
});
two.Property(p => p.TwoId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
two.HasRequired(t => t.Three)
.WithMany(s => s.Twos)
.HasForeignKey(t => t.ThreeId);
var three = modelBuilder.Entity<Three>();
three.ToTable("Three");
three.HasKey(s => s.ThreeId);
three.Property(p => p.ThreeId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
base.OnModelCreating(modelBuilder);
}
}
Finally, this is a snippet of code to cause the exception:
using (var ctx = new DbCtx(#"....."))
{
Console.WriteLine(ctx.Twos.Count());
}
The reason for the error are incorrectly configured relations in your model. This is not correct:
one.HasRequired(t => t.Two)
.WithMany(s => s.Ones)
.HasForeignKey(t => t.TwoId);
one.HasRequired(t => t.Three)
.WithMany(s => s.Ones)
.HasForeignKey(t => t.ThreeId);
It should be:
one.HasRequired(t => t.Two)
.WithMany(s => s.Ones)
.HasForeignKey(t => new { t.TwoId, t.ThreeId });
Because dependent's FK must contain all columns of principal PK. You must also remove navigation property from Three to One.
This can also be caused by Code first from Database.
I had several views that I brought in that did not have an obvious key field according to Entity Framework conventions. The code generated put the [Key] attribute on the wrong field. In fact, it could not detect any uniqueness, so it put the [Key] attribute on all the fields.
I was able to remove all of the extra Key attributes to make the error go away.
Note for EF5+:
.HasForeignKey has been deprecated from EF 5: List of available methods (https://msdn.microsoft.com/en-us/library/system.data.entity.modelconfiguration.configuration.manytomanyassociationmappingconfiguration_methods(v=vs.103).aspx)
- MapLeftKey
- MapRightKey
- ToTable
If one were to need Many to Many where one 'Many' is to an Entity with a CompositeKey is:
one.HasKey(t => new { t.TwoId, t.ThreeId });
one.HasRequired(t => t.Two)
.WithMany(s => s.Ones)
.Map(m=>m.MapLeftKey("OneId").MapRIghtKey(new string[]{"TwoId", "ThreeId"}))