Entity Framework Code First: настройка взаимной связи "один-на-один" с использованием аннотаций
У меня есть два объекта, которые я пытаюсь связать (один к одному) с использованием ассоциаций внешних ключей.
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; }
}
Это исключает исключение ModelValidationException. Любые идеи, почему такое, казалось бы, простое взаимно однозначное отношение "один к одному" не могут быть настроены.
Edit:
Вот Исключение:
System.Data.Entity.ModelConfiguration.ModelValidation Исключение было обнаружено Сообщение = Во время генерации модели были обнаружены одна или несколько ошибок проверки:
System.Data.Edm.EdmAssociationEnd:: множественность недействительна в роли "StandardRelay_StandardRack_Source" в отношении "StandardRelay_StandardRack". Поскольку свойства зависимой роли не являются ключевыми свойствами, верхняя граница множественности зависимой роли должна быть *.
Источник = EntityFramework Трассировки стека: в System.Data.Entity.ModelConfiguration.Edm.EdmModelExtensions.ValidateAndSerializeCsdl(модель EdmModel, создатель XmlWriter) в System.Data.Entity.ModelConfiguration.Edm.EdmModelExtensions.ValidateCsdl(модель EdmModel) в System.Data.Entity.DbModelBuilder.Build(DbProviderManifest providerManifest, DbProviderInfo providerInfo) в System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection) в System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext) в 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() в System.Data.Entity.Internal.Linq.InternalSet 1.GetEnumerator()
at System.Data.Entity.Infrastructure.DbQuery
1.System.Collections.Generic.IEnumerable.GetEnumerator() в коллекции System.Collections.Generic.List 1..ctor(IEnumerable
1) в System.Linq.Enumerable.ToList [TSource] (источник IEnumerable`1) в TestApplication.MainWindow.Window_Loaded (отправитель объекта, RoutedEventArgs e) в D:\RailwayProjects\RelayAnalysis\TestApplication\MainWindow.xaml.cs: строка 33 InnerException:
Ответы
Ответ 1
Я думаю, что foreignKey должен быть Id, а не StandardRack_id.
Кроме того, вы должны использовать виртуальные, чтобы иметь возможность использовать ленивую загрузку.
Это работает для меня
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();
}
}
}
Ответ 2
Индивидуальные ассоциации внешних ключей не поддерживаются Entitiy Framework. Вы должны удалить внешний ключ и использовать общие первичные ключи (первичный ключ зависимого - это его внешний ключ для принципала одновременно):
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; }
}
Отображение в Fluent API:
modelBuilder.Entity<StandardRack>()
.HasOptional(rack => rack.StandardRelay)
.WithRequired(relay => relay.StandardRack);
(Я утверждаю, что StandardRack
имеет необязательное реле.)
Ответ 3
Вот как вы можете указать отношения "один к одному" с FK, используя беглый api.
Обратите внимание, что FK явно не определен в Enitity, но он определен с использованием свободного 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")));
Свободный api добавит столбец StandardRack_Id
в StandardRelay
.
Обратите внимание, что имя метода WithOptionalPrincipal() довольно иронично. msdn документация WithOptionalDependent должна прояснить.
Ответ 4
Возможно, вы захотите адаптировать аннотацию ID в StandardRelay. Также см. Этот связанный вопрос:
Что означает основной конец ассоциации в соотношении 1:1 в структуре Entity
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;}
}