【问题标题】:Issue with 1 to many relationship through code first首先通过代码解决一对多关系问题
【发布时间】:2013-03-04 00:21:05
【问题描述】:

我刚刚问了question 并得到了解决方案,但解决方案产生了一个我在这里提到的新问题。在这里,我修改了我的代码并在AccountHolderNominee 之间创建了一个新的一对一关系。

public partial class AccountHolder
{
    public int AccountHolderId { get; set; }

    public virtual List<Address> Address { get; set; }
    public virtual Nominee Nominee { get; set; }
}

public partial class Nominee
{
    public int NomineeId { get; set; }

    public virtual List<Address> Address { get; set; }
}

public partial class Address
{
    public int AddressId { get; set; }    

    public int AccountHolderId { get; set; }
    public AccountHolder AccountHolder { get; set; }

    public int NomineeId { get; set; }
    public Nominee Nominee { get; set; }
}

它们之间的关系如下:

  1 to many between AccountHolder and Address
  1 to many between Nominee and Address
  1 to 1 between AccountHolder and Nominee

流利的Api代码是:

        modelBuilder.Entity<AccountHolder>().HasOptional(p => p.Nominee)
                                            .WithRequired()
                                            .WillCascadeOnDelete(false);
        modelBuilder.Entity<Address>().HasRequired(p => p.AccountHolder)
                                      .WithMany(p => p.Address)
                                      .HasForeignKey(p => p.AccountHolderId)
                                      .WillCascadeOnDelete();
        modelBuilder.Entity<Address>().HasRequired(p => p.Nominee)
                                      .WithMany(p => p.Address)
                                      .HasForeignKey(p => p.NomineeId)
                                      .WillCascadeOnDelete();

首先,如果有任何改进的范围,请建议我。现在我在这里面临的问题是,每当我插入AccountHolder 时,我必须创建一个Nominee 的空实例,而在插入Nominee 时,我必须创建AccountHolder 的空实例。如果我不这样做,就会发生我在上一个问题中提到的错误。谁能指导我如何解决这个问题,请在您的解决方案中添加示例代码。

我用于插入数据的代码是:

var accountHolder = new AccountHolder() { 
                      AccountHolderId = 901, 
                      Address = new List<Address>() 
                      { 
                        new Address() 
                        { 
                          HouseNumber = hnumber, 
                          Street = street, 
                          Nominee = new Nominee() //this is the issue
                        } 
                      }, 
                      Nominee = new Nominee() 
                      {  
                          Address = new List<Address>() 
                          {
                             new Address() 
                             { 
                               HouseNumber = n_hnumber, 
                               Street = n_street, 
                               AccountHolder = new AccountHolder() //this is the issue
                             } 
                          } 
                       } 
};

谢谢!

【问题讨论】:

  • 嘿,我试过你的代码。并添加了一个新的账户持有人,只提供了 accountHolderId,它对我有用。顺便说一句,从逻辑上讲,您的类和关系是错误的,但从语法上讲它们是正确的
  • 当您为账户持有人插入地址时会出现问题,您能告诉我我的课程逻辑有什么问题吗?
  • 那是因为,您的地址表需要依赖于两个 FK,AddressId 和 NomineeId。地址表的任何条目都将首先需要这两个。所以你必须为他们中的任何一个输入 Nominee 和 Address
  • 从逻辑上讲,Address 应该始终是独立的,您的 AccountHolder 和被提名人应该依赖于 Address 而不是相反。否则,你将不得不做你现在正在做的事情,创建所有实体对象就足够了

标签: c# sql code-first


【解决方案1】:

好的,我终于找到了解决方案,但如果有比请建议我更好的解决方案。我所做的是在地址表中创建 FK 可选(可为空):

班级变化:

public partial class Address
{
    public int AddressId { get; set; }    

    public int? AccountHolderId { get; set; }
    public AccountHolder AccountHolder { get; set; }

    public int? NomineeId { get; set; }
    public Nominee Nominee { get; set; }
}

fluent api 的变化:

modelBuilder.Entity<AccountHolder>().HasOptional(p => p.Nominee)
                                            .WithRequired()
                                            .WillCascadeOnDelete(false);
        modelBuilder.Entity<Address>().HasOptional(p => p.AccountHolder)
                                      .WithMany(p => p.Address)
                                      .HasForeignKey(p => p.AccountHolderId)
                                      .WillCascadeOnDelete();
        modelBuilder.Entity<Address>().HasOptional(p => p.Nominee)
                                      .WithMany(p => p.Address)
                                      .HasForeignKey(p => p.NomineeId)
                                      .WillCascadeOnDelete();

【讨论】:

    【解决方案2】:

    据我了解您的需求,以下运行。

    请注意,设置 AccountHolderId 有点困难,因为与 nominee 是一对一的关系,Nominee 的 PK 也是一个 FK。

    using System;
    using System.Linq;
    using System.Data.Entity;
    using System.Data.Entity.ModelConfiguration;
    using System.ComponentModel.DataAnnotations;
    using System.Collections.Generic;
    
    namespace testEF {
        class Program {
            static void Main(string[] args) {
                using ( EFContext efc = new EFContext() ) {
                    var AHAddress = new Address {
                        AddressId = 1,
                        HouseNumber = "150",
                        Street = "street",
                    };
                    var AHNominee = new Nominee {
                        NomineeId = 1,
                        Address = new List<Address>() { 
                            AHAddress
                        }};                
                    var accountHolder = new AccountHolder() {
                        Address = new List<Address>() { 
                            AHAddress
                        },
                        Nominee = AHNominee
                    };
                    efc.Holders.Add(accountHolder);
                    efc.SaveChanges();
    
                    foreach (AccountHolder ah in efc.Holders) {
                        Console.WriteLine("{0} -> {1}", ah.AccountHolderId, ah.Nominee.NomineeId);
                    }
                };
            }
        }
    
        public partial class AccountHolder {
            public int AccountHolderId { get; set; }
    
            public virtual List<Address> Address { get; set; }
            public virtual Nominee Nominee { get; set; }
        }
    
        public partial class Nominee {
            public int NomineeId { get; set; }
    
            public virtual List<Address> Address { get; set; }
        }
    
        public partial class Address {
            public int AddressId { get; set; }
    
            public String HouseNumber { get; set; }
            public String Street { get; set; }
    
            public int AccountHolderId { get; set; }
            public AccountHolder AccountHolder { get; set; }
    
            public int NomineeId { get; set; }
            public Nominee Nominee { get; set; }
        }
    
    
        public class EFContext : DbContext {
            public IDbSet<AccountHolder> Holders { get; set; }
    
            public EFContext()
                : base() {
                Database.SetInitializer<EFContext>(new DropCreateDatabaseAlways<EFContext>());
            }
    
            protected override void OnModelCreating(DbModelBuilder modelBuilder) {
                base.OnModelCreating(modelBuilder);
    
                modelBuilder.Entity<AccountHolder>().HasOptional(p => p.Nominee)
                                                .WithRequired()
                                                .WillCascadeOnDelete(false);
                modelBuilder.Entity<Address>().HasRequired(p => p.AccountHolder)
                                              .WithMany(p => p.Address)
                                              .HasForeignKey(p => p.AccountHolderId)
                                              .WillCascadeOnDelete();
                modelBuilder.Entity<Address>().HasRequired(p => p.Nominee)
                                              .WithMany(p => p.Address)
                                              .HasForeignKey(p => p.NomineeId)
                                              .WillCascadeOnDelete();
            }
        }    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多