2011-05-09 15 views
6

ile birden birçok birime bir yapılandırma nasıl Adresleri bir koleksiyon başvuran bir müşteri varlık var. Buradaki karmaşıklık, belirli bir adresi varsayılan adres olarak tanımlamak istiyorum. EF Kod İlk 4.1 - varsayılan

Müşteri tablosunda varsayılan adresi FK tutmak istiyoruz Mümkünse

. Bu, varsayılanları tanımlamak için adresler tablosunda bir sütuna sahip olmaktan daha zarif görünüyor.

Bu ilişkiyi tanımlayan bakımından akıcı API ile zorluk yaşıyorum. Aşağıdaki kodu çalıştırdığımda bir özel durum alıyorum: "İlişkileri için yabancı anahtar özelliklerini göstermeyen varlıklar kaydedilirken bir hata oluştu. EntityEntries özelliği, tek bir varlığın kaynağı olarak tanımlanamadığı için null döndürecektir. istisnai durumlar: Tasarruf sırasında istisnaların ele alınması, varlık türlerinizde yabancı anahtar özelliklerinin ifşa edilmesiyle daha kolay yapılabilir. Ayrıntılar için InnerException bölümüne bakın. " "bağımlı işlemler için geçerli bir sıralamayı belirlenemedi. Bağımlılıklar nedeniyle yabancı anahtar kısıtlamaları, model gereksinimleri, veya mağaza tarafından oluşturulan değerlere var olabilir."

ben kesin sorunu göstermek için bir konsol uygulaması oluşturulur. Bu test uygulamasında bir Müşteri var, bir Adres ve flient api yapılandırmam var.

Herhangi bir yardım çok takdir:

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(); 
     } 
    } 
} 

çok teşekkür ederiz,

Paul.

cevap

7

EF, istisnada "yabancı anahtarların açığa çıkmaması" ile ilgili olarak orada neyin konuştuğunu anlamıyorum. İçsel istisnayı önemli kısım olarak düşünürdüm:

Geçerli işlemler için bağımlı bir işlem için belirlenemiyor. Bağımlılıklar , yabancı anahtar kısıtlamaları, model gereksinimleri veya deposu tarafından oluşturulan değerleri mevcut olabilir.

Ben senin modelinde sorun Customer ve Address arasındaki karşılıklı bağımlılığı olduğunu düşünüyorum: Bir adres bir müşteri ihtiyaçları (eğer olarak işaretlediğiniz harita oluşturma kodu gerekli) ve diğer yandan a üzerinde Müşterinin bir adrese ihtiyacı vardır (varsayılan adres numaralı numaralı telefonun null olmayan null anahtarından ve eşleme kodunuzdan dolayı). Yani, EF örnek kodunuzda hangi varlığın ilk kaydedileceğini bilmiyor - varsayılan adres veya müşteri? Her iki tarafın da geçerli FK sözleşmeleriyle kaydedilecek olan diğerinin birincil anahtarına ihtiyacı vardır.

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 { ... } set { ... } } 
    public Address DefaultAddress { get; set; } 
    public int? DefaultAddressId { get; set; } // FK for optional relationship 
} 

public class Address 
{ 
    public int Id { get; set; } 
    public string Town { get; set; } 
    public Customer Customer { get; set; } 
} 

// ... 

public class CustomerConfiguration : EntityTypeConfiguration<Customer> 
{ 
    public CustomerConfiguration() : base() 
    { 
     Property(p => p.CompanyName) 
      .HasColumnName("Name") 
      .IsRequired(); 

     HasMany(c => c.Addresses) 
      .WithRequired(a => a.Customer) 
      .Map(x => x.MapKey("CustomerId")); 
    } 
} 

public class AddressConfiguration : EntityTypeConfiguration<Address> 
{ 
    public AddressConfiguration() : base() 
    { 
     Property(p => p.Town) 
      .HasColumnName("Town") 
      .IsRequired(); 
    } 
} 

Sonra program gibi görünecektir: Görebildiğim

en kolay çözüm modelinde varsayılan adres isteğe yapmak ve sonra iki kez kurtarmak olduğunu (ki zaten Kongre tarafından hangi iş eşleştirmeleri ihmal) Bu:

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; 
    //We don't set the default address here as SaveChanges would throw an 
    //exception. But because it is optional now we are allowed to leave it null. 

    MyContext context = new MyContext(ConnectionString); 
    context.Customers.Add(headOffice); 
    context.SaveChanges(); 

    headOffice.DefaultAddress = address; // headoffice and address have now PKs 
    context.SaveChanges(); // Updates headoffice in the DB with default address 
} 

Bu çift SaveChanges çirkin, ama başka bir yol göremiyorum.

+0

Bunun için teşekkürler, burada ne dediğinizi anlamlandırıyor.Bunu deneyeceğim ve nasıl devam ettiğimi burada güncelleyeceğim. – P2l

+0

Şimdi bunu test ettim ve bizim için çalışıyor. Dediğin gibi, çirkin ama başka bir yaklaşım göremiyorum. Yardım ettiğin için teşekkür ederim. – P2l