Tengo una entidad Cliente que hace referencia a una colección de Direcciones. La complicación aquí es que quiero poder identificar una dirección particular como la dirección predeterminada.Código EF Primero 4.1 - Cómo configurar una relación de uno a muchos con el valor predeterminado
De ser posible, me gustaría mantener el FK de la dirección predeterminada en la tabla Cliente. Esto parece más elegante que tener una columna en la tabla de direcciones para identificar el valor predeterminado.
Tengo dificultades con la API fluida en términos de definición de esta relación. Cuando ejecuto el siguiente código, recibo una excepción que dice: "Se produjo un error al guardar entidades que no exponen propiedades de claves foráneas para sus relaciones. La propiedad EntityEntries devolverá nulo porque no se puede identificar una sola entidad como fuente de la excepción. El manejo de excepciones mientras se guarda puede ser más fácil al exponer propiedades de claves foráneas en sus tipos de entidades. Consulte InnerException para más detalles. " "No se puede determinar un pedido válido para las operaciones dependientes. Las dependencias pueden existir debido a restricciones de clave externa, requisitos del modelo o valores generados en la tienda".
Creé una aplicación de consola para mostrar el problema exacto. En esta aplicación de prueba tengo una entidad de Cliente, una Dirección y la configuración de API de flient.
Cualquier ayuda sería muy apreciada:
using System;
using System.Collections.Generic;
using System.Data.Entity.ModelConfiguration;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
namespace OneToManyWithDefault
{
public class Customer
{
private ICollection<Address> m_Addresses;
public Customer()
{
Addresses = new List<Address>();
}
public int Id { get; set; }
public string CompanyName { get; set; }
public virtual ICollection<Address> Addresses
{
get
{
if (m_Addresses == null)
{
m_Addresses = new List<Address>();
}
return m_Addresses;
}
set
{
m_Addresses = value;
}
}
public Address DefaultAddress { get; set; }
public int DefaultAddressId { get; set; }
}
public class Address
{
public int Id { get; set; }
public string Town { get; set; }
public Customer Customer { get; set; }
}
public class MyContext
: DbContext
{
public DbSet<Customer> Customers { get; set; }
public MyContext(string connectionString)
: base(connectionString)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new CustomerConfiguration());
modelBuilder.Configurations.Add(new AddressConfiguration());
base.OnModelCreating(modelBuilder);
}
}
public class CustomerConfiguration
: EntityTypeConfiguration<Customer>
{
public CustomerConfiguration()
: base()
{
HasKey(p => p.Id);
Property(p => p.Id)
.HasColumnName("Id")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
.IsRequired();
Property(p => p.CompanyName)
.HasColumnName("Name")
.IsRequired();
// Configure the mapping for the Default Address (this is likely to be wrong!):
HasRequired(p => p.DefaultAddress).WithMany()
.Map(x => x.MapKey("DefaultAddressId"))
.WillCascadeOnDelete(false);
HasRequired(p => p.DefaultAddress)
.WithMany()
.HasForeignKey(x => x.DefaultAddressId);
ToTable("Customers");
}
}
public class AddressConfiguration
: EntityTypeConfiguration<Address>
{
public AddressConfiguration()
: base()
{
HasKey(p => p.Id);
Property(p => p.Id)
.HasColumnName("Id")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
.IsRequired();
Property(p => p.Town)
.HasColumnName("Town")
.IsRequired();
HasRequired(p => p.Customer)
.WithMany(c => c.Addresses)
.Map(x => x.MapKey("CustomerId"));
ToTable("Addresses");
}
}
class Program
{
private const string ConnectionString =
@"Server=.\sql2005;Database=OneToManyWithDefault;integrated security=SSPI;";
static void Main(string[] args)
{
Customer headOffice = new Customer();
headOffice.CompanyName = "C1";
Address address = new Address();
address.Town = "Colchester";
headOffice.Addresses.Add(address);
address = new Address();
address.Town = "Norwich";
headOffice.Addresses.Add(address);
headOffice.DefaultAddress = address;
MyContext context = new MyContext(ConnectionString);
context.Customers.Add(headOffice);
context.SaveChanges();
Console.WriteLine("Done.");
Console.ReadLine();
}
}
}
Muchas gracias,
Paul.
Gracias por esto, tiene sentido lo que dices aquí.Voy a probar esto y actualizar aquí con la forma en que avanzo. – P2l
He probado esto y funciona para nosotros. Como dices, es feo pero no puedo ver otro enfoque. Gracias por tu ayuda. – P2l