所以,我有两个主要的对象,Member和Guild。一个Member可以拥有一个Guild,而一个Guild可以有多个Members。
我把Members类放在了一个单独的DbContext和单独的类库中。我计划在多个项目中重复使用这个类库,并为了区分不同的项目,将数据库模式设置为“acc”。我已经对这个库进行了广泛的测试,并且可以在acc.Members表中添加、删除和更新Members。
Guild类如下:
public class Guild
{
public Guild()
{
Members = new List<Member>();
}
public int ID { get; set; }
public int MemberID { get; set; }
public virtual Member LeaderMemberInfo { get; set; }
public string Name { get; set; }
public virtual List<Member> Members { get; set; }
}
使用以下映射:
internal class GuildMapping : EntityTypeConfiguration<Guild>
{
public GuildMapping()
{
this.ToTable("Guilds", "dbo");
this.HasKey(t => t.ID);
this.Property(t => t.MemberID);
this.HasRequired(t => t.LeaderMemberInfo).WithMany().HasForeignKey(t => t.MemberID);
this.Property(t => t.Name);
this.HasMany(t => t.Members).WithMany()
.Map(t =>
{
t.ToTable("GuildsMembers", "dbo");
t.MapLeftKey("GuildID");
t.MapRightKey("MemberID");
});
}
}
但是,当我尝试创建一个新的公会时,它显示没有dbo.Members。
我参考了Member的EF项目,并将Members类的映射添加到了Guild类所在的DbContext中。modelBuilder.Configurations.Add(new MemberMapping());
(不确定这是否是最佳方法。)
这导致了以下错误:
{"The member with identity 'GuildProj.Data.EF.Guild_Members' does not exist in the metadata collection.\r\nParameter name: identity"}
如何在不同的数据库架构和DbContext之间利用这两个表之间的外键?
更新
我找到了错误的原因。当我创建新公会时,我将公会领袖的成员ID设置为MemberID。这很好地运行。但是,当我尝试将该领导者的成员对象添加到公会成员列表(Members)中时,就会出现错误。
更新2
这是我创建Guild类所在的上下文的代码。(由Hussein Khalil请求)
public class FSEntities : DbContext
{
public FSEntities()
{
this.Configuration.LazyLoadingEnabled = false;
Database.SetInitializer<FSEntities>(null);
}
public FSEntities(string connectionString)
: base(connectionString)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new GuildMapping());
modelBuilder.Configurations.Add(new KeyValueMappings());
modelBuilder.Configurations.Add(new LocaleMappings());
modelBuilder.Configurations.Add(new MemberMapping());
}
public DbSet<Guild> Guilds { get; set; }
public DbSet<KeyValue> KeyValues { get; set; }
public DbSet<Locale> Locales { get; set; }
}
这是我在代码库中保存它的方式:
public async Task CreateGuildAsync(Guild guild)
{
using (var context = new FSEntities(_ConnectionString))
{
context.Entry(guild.Members).State = EntityState.Unchanged;
context.Entry(guild).State = EntityState.Added;
await context.SaveChangesAsync();
}
}
最终解决方案
因此,我不得不在DbContext中为包含Guild
的Member
、Role
和Permission
添加映射。我不得不添加Role
和Permission
,因为Member
有List<Role> Roles
,而每个Role
都有List<Permission> Permissions
。
这让我更接近解决方案。但我仍然会遇到诸如以下错误:
{"The member with identity 'GuildProj.Data.EF.Member_Roles' does not exist in the metadata collection.\r\nParameter name: identity"}
在这里,当你从 Session
中获取成员时,你会得到类似以下的内容:
System.Data.Entity.DynamicProxies.Member_FF4FDE3888B129E1538B25850A445893D7C49F878D3CD40103BA1A4813EB514C
Entity Framework似乎不能很好地处理这个问题。为什么?我不确定,但我认为这是因为ContextM创建了Member的代理,并通过将Member克隆到一个新的Member对象中,使ContextM不再具有关联。我认为这样可以让ContextG自由使用新的Member对象。我尝试在我的DbContexts中设置ProxyCreationEnabled = false,但从Session中提取的Member对象仍然是System.Data.Entity.DynamicProxies.Member类型。
所以,我做的是:
Member member = new Member((Member)Session[Constants.UserSession]);
我不得不在各自的构造函数中克隆每个Role
和Permission
。
这让我接近成功,但我还需要修改我的仓库以及保存Guild
对象的方式。
context.Entry(guild.LeaderMemberInfo).State = EntityState.Unchanged;
foreach(var member in guild.Members)
{
context.Entry(member).State = EntityState.Unchanged;
}
context.Entry(guild).State = EntityState.Added;
await context.SaveChangesAsync();
Member
类呢?虽然在不同的上下文中映射是不同的,而且一个Member
对象如果没有从第一个上下文中分离出来就无法在上下文之间传输,但这似乎是可能的。 - jjj