I have following two Entities that I am trying to relate (one to one) using foreign key associations.
public class StandardRack {
public int Id {get;set}
public StandardRelay StandardRelay {get;set}
}
public class StandardRelay {
public int Id {get;set}
public int StandardRack_Id {get;set;}
[Required][ForeignKey("StandardRack_Id")]
public StandardRack StandardRack { get; set; }
}
This throws ModelValidationException. Any ideas why such a seemingly simple one-to-one bidirectional relationship cannot be configured.
Edit:
Here is the Exception:
System.Data.Entity.ModelConfiguration.ModelValidationException was caught Message=One or more validation errors were detected during model generation:
System.Data.Edm.EdmAssociationEnd: : Multiplicity is not valid in Role 'StandardRelay_StandardRack_Source' in relationship 'StandardRelay_StandardRack'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be �*�.
Source=EntityFramework StackTrace: at System.Data.Entity.ModelConfiguration.Edm.EdmModelExtensions.ValidateAndSerializeCsdl(EdmModel model, XmlWriter writer) at System.Data.Entity.ModelConfiguration.Edm.EdmModelExtensions.ValidateCsdl(EdmModel model) at System.Data.Entity.DbModelBuilder.Build(DbProviderManifest providerManifest, DbProviderInfo providerInfo) at System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection) at System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext) at System.Data.Entity.Internal.RetryLazy
2.GetValue(TInput input) at System.Data.Entity.Internal.LazyInternalContext.InitializeContext() at System.Data.Entity.Internal.InternalContext.Initialize() at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType) at System.Data.Entity.Internal.Linq.InternalSet
1.Initialize() at System.Data.Entity.Internal.Linq.InternalSet1.GetEnumerator() at System.Data.Entity.Infrastructure.DbQuery
1.System.Collections.Generic.IEnumerable.GetEnumerator() at System.Collections.Generic.List1..ctor(IEnumerable
1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) at TestApplication.MainWindow.Window_Loaded(Object sender, RoutedEventArgs e) in D:\RailwayProjects\RelayAnalysis\TestApplication\MainWindow.xaml.cs:line 33 InnerException:
I think the foreignKey should be Id, not StandardRack_id. Also, you should use virtual, in order to be able to use lazy loading.
This works for me
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
namespace Racks
{
public class StandardRack
{
public int Id { get; set; }
public virtual StandardRelay StandardRelay { get; set; }
}
public class StandardRelay
{
public int Id { get; set; }
public int StandardRack_Id { get; set; }
[ForeignKey("Id")]
[Required]
public virtual StandardRack StandardRack { get; set; }
}
public class Context : DbContext
{
static Context()
{
Database.SetInitializer<Context>(null);
}
public DbSet<StandardRack> StandardRacks { get; set; }
public DbSet<StandardRelay> StandardRelays { get; set; }
}
class Program
{
static void Main(string[] args)
{
var context = new Context();
context.Database.Delete();
context.Database.Create();
var standardRack = new StandardRack();
standardRack.StandardRelay = new StandardRelay();
context.StandardRacks.Add(standardRack);
context.SaveChanges();
}
}
}
One-to-one foreign key associations are not supported by Entitiy Framework. You must remove the foreign key and use shared primary keys (primary key of the dependent is its foreign key to the principal at the same time):
public class StandardRack {
public int Id {get;set}
public StandardRelay StandardRelay {get;set}
}
public class StandardRelay {
public int Id {get;set}
public StandardRack StandardRack { get; set; }
}
Mapping in Fluent API:
modelBuilder.Entity<StandardRack>()
.HasOptional(rack => rack.StandardRelay)
.WithRequired(relay => relay.StandardRack);
(I'm assuing here that a StandardRack
has an optional Relay.)
Here is how you can specify one-to-one relationship with FK using fluent api.
Note that FK is not explicitly defined in Enitity, but it's defined using fluent api.
public class StandardRack {
public int Id {get;set}
public StandardRelay StandardRelay {get;set}
}
public class StandardRelay {
public int Id {get;set}
public StandardRack StandardRack { get; set; }
}
modelBuilder.Entity<StandardRack>()
.HasOptional(x => x.StandardRelay)
.WithOptionalPrincipal(y => y.StandardRack)
.Map(configurationAction: new Action<ForeignKeyAssociationMappingConfiguration>(x => x.MapKey("StandardRack_Id")));
fluent api will add column StandardRack_Id
in StandardRelay
.
Note that method name WithOptionalPrincipal() is quite ironic. msdn documentation of WithOptionalDependent shall make it clear.
You might want to adapt the annotation of ID in StandardRelay. Also see this related question:
What does principal end of an association means in 1:1 relationship in Entity framework
public class Foo
{
public string FooId{get;set;}
public Boo Boo{get;set;}
}
public class Boo
{
[Key, ForeignKey("Foo")]
public string BooId{get;set;}
public Foo Foo{get;set;}
}
来源:https://stackoverflow.com/questions/10108160/entity-framework-code-first-setting-up-one-to-one-foreign-key-association-usin