如何在 FluentAPI 映射中插入数据 Table

How To Insert Data In FluentAPI Mapping Table

我有一个 A Table、B Table 和 AB(映射 Table)

A

public class A
{
    public int AID{ get; set; }

    [JsonIgnore]
    public virtual ICollection<B> Bs { get; set; }
}

B

public class B
{
    public int BID { get; set; }

    [JsonIgnore]
    public virtual ICollection<A> As { get; set; }
}

ApplicationDbContext

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<B>()
                    .HasMany(s => s.As)
                    .WithMany(c => c.Bs)
                    .Map(cs =>
                    {
                        cs.MapLeftKey("AID");
                        cs.MapRightKey("BID");
                        cs.ToTable("AB");
                    });

    }

现在一切都很好,但是我该如何插入这个 AB 映射 table?

如果我尝试如下所示创建 AB,它会生成两个 tables,AB 和 AB1,它们具有相同的列名和全部。

public class AB
{
    public int ABID { get; set; }
    public string AID { get; set; }
    public int BID { get; set; }
}
  1. 那么有没有办法在 FluentAPI Mapping 中进行 CRUD Table?
  2. 如果不是,那么我可以强制 FluentAPI 从现有 table 映射吗?在这种情况下,我将手动管理 Employee 并将更改映射代码以使用现有的 table.

我找不到任何解决方案。

编辑: 由于问题已更改,我正在写一个更详尽的答案。但是,您的问题的答案保持不变:

Now things are perfectly fine, but how do I insert in this AB Mapping table?

你没有!

这正是 EF 擅长的事情。现在您不需要自己管理 link table,而是最终得到您想要的实际对象。所以,如果你想在 AB 之间添加一个 link,你所做的就是将 B 添加到那个 [=] 上的 Bs 集合14=]。您永远不会直接插入 AB table,因为谁在乎呢? table 在那里,所以我们可以在不同的 AB 之间建立关系,仅此而已。因此,Entity Framework 将创建供自己使用的 table,但不会将其呈现给您,因为这不是 EF 的工作方式:您使用对象并让 EF 处理数据库。

这就是为什么当您尝试自己定义 table 时,它会创建两个:它已经在创建一个名为 AB 的 table,但您要求另一个。它不能具有完全相同的名称,因此它会在其末尾附加一个“1”。由于您已经使用 FluentAPI 来定义应用程序,因此让 EF 担心如何实现映射:您需要关心的是,您现在有一种方法可以让 A 具有一组 Bs,反之亦然。

由于这听起来仍然与名称 'A' 和 'B' 混淆,下面是控制台应用程序的 Program class 来说明这一点;您需要做的就是启动一个新的控制台应用程序,用这个替换程序 class,安装 entity framework 包,然后 运行 enable-migrations -enableautomaticmigrations -force。我建议您使用它来添加一些对象并关联它们,然后查看您的数据库:您将看到 'AB' table,其中包含已添加的记录。这可能有助于更好地解释它。

class Program
{
    static bool quit = false;
    static void Main(string[] args)
    {
        string s = "Please select an option:" +
                   "\n1: Insert an A" +
                   "\n2: Insert a B" + 
                   "\n3: Add a B to an A" +
                   "\n4: Add an A to a B" +
                   "\n5: Print all As" +
                   "\n6: Print all Bs" +
                   "\n7: Print AB Table" +
                   "\nx: Quit.";


        while (!quit)
        {
            Console.WriteLine();
            Console.WriteLine(s);
            var k = Console.ReadKey();
            DoStuff(k);
        }
    }

    private static void DoStuff(ConsoleKeyInfo i)
    {
        switch (i.Key)
        {
            case ConsoleKey.D1:
                //add an A  
                AddA(GetName());
                break;
            case ConsoleKey.D2:
                //add a B
                AddB(GetName());
                break;
            case ConsoleKey.D3:
                // link a B to an A
                LinkB(GetBtoLink(),GetAtoLink());
                break;
            case ConsoleKey.D4:
                //link an A to an B
                LinkA(GetAtoLink(), GetBtoLink());
                break;
            case ConsoleKey.D5:
                // print As
                WriteA();
                break;
            case ConsoleKey.D6:
                //print Bs
                WriteB();
                break;
            case ConsoleKey.D7:
                // print AB
                WriteAB();
                break;
            case ConsoleKey.X:
                quit = true;
                break;
        }
    }

    private static int GetAtoLink()
    {
        string x;
        int z;


        do
        {
            Console.Clear();
            Console.WriteLine("Please enter the ID of the A you want to use and then press enter.");
            WriteA();
            x = Console.ReadLine();
        } while (!int.TryParse(x, out z));

        return z;
    }

    private static int GetBtoLink()
    {
        string x;
        int z;


        do
        {
            Console.Clear();
            Console.WriteLine("Please enter the ID of the B you want to use and then press enter.");
            WriteB();
            x = Console.ReadLine();
        } while (!int.TryParse(x, out z));

        return z;
    }

    private static void WriteB()
    {         
        Console.WriteLine("{0,10}{1,15}", "ID", "Name");
        using (var db = new Context())
        {
            foreach (var a in db.Bs)
            {
                Console.WriteLine("{0,10}{1,15}", a.BID, a.Name);
            }
        }
    }

    private static void WriteA()
    {
        Console.WriteLine("{0,10}{1,15}", "ID", "Name");
        using (var db = new Context())
        {
            foreach (var a in db.As)
            {
                Console.WriteLine("{0,10}{1,15}", a.AID, a.Name);
            }
        }
    }

    private static void WriteAB()
    {
        Console.WriteLine("{0,10}{1,10}", "AID", "BID");
        using (var db = new Context())
        {
            // this is the only way we need to do this, because it's many to many, 
            // if an A is linked to a B, then that B is by definition linked to that A as well.
            foreach (var a in db.As)
            {
                foreach (var b in a.Bs)
                {
                    Console.WriteLine("{0,10}{1,10}", a.AID, b.BID);
                }

            }
        }
    }


    private static void LinkB(int bToUse, int aToUse)
    {
        using (var db = new Context())
        {
            var a = db.As.First(x => x.AID == aToUse);
            var b = db.Bs.First(y => y.BID == bToUse);
            a.Bs.Add(b);
            db.SaveChanges();
        }
    }

    private static void LinkA(int aToUse, int bToUse)
    {
        using (var db = new Context())
        {
            var a = db.As.First(x => x.AID == aToUse);
            var b = db.Bs.First(y => y.BID == bToUse);
            b.As.Add(a);
            db.SaveChanges();
        }
    }

    private static string GetName()
    {
        Console.WriteLine("Please enter a name");
        return Console.ReadLine();
    }

    private static void AddA(string input)
    {
        using (var db = new Context())
        {
            db.As.Add(new A {Name = input});
            db.SaveChanges();
        }
    }

    private static void AddB(string input)
    {
        using (var db = new Context())
        {
            db.Bs.Add(new B { Name = input });
            db.SaveChanges();
        }
    }
}

public class A
{
    public int AID { get; set; }
    public string Name { get; set; }


    public virtual ICollection<B> Bs { get; set; }
}

public class B
{
    public int BID { get; set; }
    public string Name { get; set; }


    public virtual ICollection<A> As { get; set; }
}

public class Context : DbContext
{


    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<B>()
                    .HasMany(s => s.As)
                    .WithMany(c => c.Bs)
                    .Map(cs =>
                    {
                        cs.MapLeftKey("AID");
                        cs.MapRightKey("BID");
                        cs.ToTable("AB");
                    });

    }

    public DbSet<A> As { get; set; }
    public DbSet<B> Bs { get; set; }  
}

旧答案: 您在 Company 中定义了一个名为 EmployeesICollection<ApplicationUser>,并使用 FluentAPI 映射到它。这会按预期创建一个名为 'Employees' 的 table。您不必创建另一个名为 Employees 的 class;就 Entity Framework 而言,您已经告诉它创建一个名为 Employees 的 table。这就是为什么 我认为您缺少的步骤是定义您的 DbSet<>

使用您的代码 运行ning Add-Migration,这是我为员工 table 得到的定义:

CreateTable(
    "dbo.Employees",
    c => new
        {
            UserID = c.Int(nullable: false),
            CompanyID = c.Int(nullable: false),
        })
    .PrimaryKey(t => new { t.UserID, t.CompanyID })
    .ForeignKey("dbo.ApplicationUsers", t => t.UserID, cascadeDelete: true)
    .ForeignKey("dbo.Companies", t => t.CompanyID, cascadeDelete: true)
    .Index(t => t.UserID)
    .Index(t => t.CompanyID);

这似乎与您想要的相关。

要完成它,请将(如果您还没有)添加到您的 ApplicationDbContext 文件中:

public DbSet<ApplicationUser> Employees;
public DbSet<Company> Companies;  

然后要添加员工,您可以创建一个新的 ApplicationUser 并像

一样添加它
ApplicationUser user = new ApplicationUser();
// do whatever here to give it the right data

ApplicationDbContext ctx = new ApplicationDbContext();
ctx.Employees.Add(user);

Employees table 本身你不应该与之互动。

EF 将管理您不需要直接插入到映射 table 中,看看我在我的项目中的这个示例:

 public class Organization : Entity<int>
    {
        public string Name { get; set; }
        public string Address { get; set; }
        public string MainContact { get; set; }
        public string Phone { get; set; }
        public string Website { get; set; }

        //navigation property
        public virtual ICollection<DevelopmentalGoal> DevelopmentalGoals { get; set; }
        public virtual ICollection<ServiceActivity> ServiceActivities { get; set; }

    }

    public class DevelopmentalGoal : Entity<int>
    {
        public string Name { get; set; }
        public string Icon { get; set; }
        
        //navigation property
        public virtual ICollection<Organization> Organizations { get; set; }
    }



 protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {   

   modelBuilder.Entity<Organization>().ToTable("Organization", "ServiceLearning")
                .HasKey(t => t.ID);


            modelBuilder.Entity<DevelopmentalGoal>().ToTable("DevelopmentalGoal", "ServiceLearning")
                .HasKey(t => t.ID);


            modelBuilder.Entity<Organization>()
              .HasMany(t => t.DevelopmentalGoals)
              .WithMany(t=> t.Organizations)
              .Map(m =>
              {
                  m.ToTable("OrganizationDevelopmentalGoal", "ServiceLearning");
                  m.MapLeftKey("OrganizationID");
                  m.MapRightKey("DevelopmentalGoalID");
              });               

}



 public int SaveOrganization(OrganizationViewModel viewModel, IUserContext currentUser)
        {
            Organization organization;

            {

                if (viewModel.ID == 0)
                {
                    organization = ObjectMapper.MapTo<Organization>(viewModel);
                    _context.Set<Organization>().Add(organization);
                }
                else
                {
                    organization = _context.Set<Organization>()
                        .SingleOrDefault(t =>
                            t.ID == viewModel.ID
                        );

                        organization.Name = viewModel.Name;
                        organization.Address = viewModel.Address;
                        organization.MainContact = viewModel.MainContact;
                        organization.Phone = viewModel.Phone;
                        organization.Website = viewModel.Website;
                    
                    UpdateOrganizationDevelopmentalGoals(organization, viewModel);

                }

                try
                {
                    CommitChanges();
                }
                catch (DbUpdateException ex)
                {
                    if (ex.IsDuplicateException())
                        throw new KeystoneDuplicateException("A Organization with the same name already exists.");

                    throw ex;
                }

            }

            return organization.ID;
        }


   private void UpdateOrganizationDevelopmentalGoals(Organization organization, OrganizationViewModel viewModel)
        {
            var originalIdList = organization.DevelopmentalGoals.Select(d => d.ID).Distinct().ToList();
            var modifiedIdList = viewModel.DevelopmentalGoal.Where(d => d.Selected == true).Select(d => d.ID).Distinct().ToList();

            //Remove deleted Developmetal Goals.
            foreach (var id in originalIdList.Except(modifiedIdList))
                organization.DevelopmentalGoals.Remove(organization.DevelopmentalGoals.Single(d => d.ID == id));

            //Add new Developmetal Goals.
            foreach (var id in modifiedIdList.Except(originalIdList))
            {
                //Add director relationship without having to load entity.
                var d = new DevelopmentalGoal { ID = id };
                _context.Set<DevelopmentalGoal>().Attach(d);

                organization.DevelopmentalGoals.Add(d);
            }
        }

正如您在 UpdateOrganizationDevelopmentalGoals 方法中看到的那样,我没有直接从映射 table 中插入或删除数据,而是从 organization.DevelopmentalGoals 中插入和删除数据,因为我已经定义了映射table 在“OnModelCreating”上 API 流利,然后 EF 知道如何管理关系。