我有A表,B表和AB(映射表)
A
public class A
{
public int AID{ get; set; }
[JsonIgnore]
public virtual ICollection<B> Bs { get; set; }
}
乙
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 Mapping表中插入?
如果我尝试创建AB,如下所示,它会生成两个表,AB和AB1具有相同的列名和所有。
public class AB
{
public int ABID { get; set; }
public string AID { get; set; }
public int BID { get; set; }
}
我无法找到任何解决方案。
答案 0 :(得分:1)
编辑:由于问题已更改,我正在撰写更全面的答案。然而,你的问题的答案仍然是相同的:
现在情况非常好,但我如何在此AB Mapping中插入 表
你没有!
这正是EF擅长的那种东西。现在,您最终得到的是您想要的实际对象,而不是自己管理链接表。因此,如果您要在A
和B
之间添加链接,您只需在B
上的Bs
集合中添加A
即可。您不会直接插入AB
表,因为谁在乎这个?该表就在那里,所以我们可以在不同的A
和B
之间建立关系,就是这样。因此,实体框架将创建表供自己使用,但不会呈现给您,因为这不是EF的工作原理:您使用对象并让EF处理数据库。
这就是为什么当你尝试自己定义表时,它会创建两个:它已经创建了一个名为AB的表,但是你要求另一个表。它不能具有完全相同的名称,因此它会在其末尾添加“1”。由于您已经使用FluentAPI来定义应用程序,因此让EF担心如何实现映射:您需要关心的是,您现在有办法让A
具有一组{ {1}} s,反之亦然。
由于这仍然让名字'A'和'B'听起来令人困惑,下面是控制台应用程序的B
类,它将说明这一点;您需要做的就是启动一个全新的控制台应用程序,用这个替换Program类,安装实体框架包,然后运行Program
。我建议您使用它来添加一些对象并将它们联系起来,然后去查看您的数据库:您将看到“AB”表,其中包含已添加的记录。这可能有助于更好地解释它。
enable-migrations -enableautomaticmigrations -force
旧答案:您已在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; }
}
中定义了一个名为ICollection<ApplicationUser>
的{{1}},并使用FluentAPI映射到该Employees
。这会按预期创建一个名为“Employees”的表。您不必创建另一个名为Employees的类;就实体框架而言,您已经告诉它创建一个名为Employees的表。这就是为什么
我认为您缺少的步骤是定义您的Company
。
使用您的代码并运行DbSet<>
,这是我为Employees表获得的定义:
Add-Migration
这似乎与你想要的相关。
要完成此操作,请将此(如果您尚未添加)添加到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);
表本身,您不应该与之交互。