Итак, у меня есть два основных объекта: член и гильдия. Один член может владеть Гильдией, и одна Гильдия может иметь несколько Членов.
У меня есть класс Members в отдельном DbContext и отдельной библиотеке классов. Я планирую повторно использовать эту библиотеку классов в нескольких проектах и помочь дифференцировать, я установил схему базы данных "acc". Я тестировал эту библиотеку широко и могу добавлять, удалять и обновлять члены в таблице acc.Members.
Класс Гильдии таков:
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.
Я получил ссылку на проект члена EF и добавил сопоставление с классом Members в 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"}
Как я могу использовать внешний ключ между этими двумя таблицами, пересекающими DbContexts и с разными схемами базы данных?
UPDATE
Я сузил причину ошибки. Когда я создаю новую гильдию, я устанавливаю идентификатор члена лидера гильдии в MemberID. Это прекрасно работает. Но, когда я затем пытаюсь добавить этот элемент Member-лидера в список гильдий членов (членов), что вызывает ошибку.
ОБНОВЛЕНИЕ 2
Вот код того, как я создаю контекст, в котором находится класс Гильдии (по просьбе Хусейна Халила)
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();
}
}
ЗАКЛЮЧИТЕЛЬНОЕ РЕШЕНИЕ
Итак, мне пришлось добавлять сопоставления к Member
, Role
и Permission
в DbContext, которые содержали Guild
. Мне пришлось добавить роль и разрешение, потому что у члена был List<Role> Roles
, и каждая роль имела 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
Сущность Framework, похоже, не очень хорошо справляется с этим. Зачем? Я не уверен, но я думаю, что это потому, что ContextM создает прокси-член Member и клонирует член в новый объект-член, ContextM больше не имеет ассоциации. Это, я думаю, позволяет ContextG свободно использовать новый объект Member. Я попытался установить ProxyCreationEnabled = false в своих DbContexts, но объект Member, который вытащил из сеанса, продолжал быть типа System.Data.Entity.DynamicProxies.Member.
Итак, я сделал это:
Member member = new Member((Member)Session[Constants.UserSession]);
Мне пришлось клонировать каждый Role
и каждый Permission
, а также внутри их соответствующих конструкторов.
Это помогло мне на 99%. Мне пришлось изменить свое репо и как я сохранил объект 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();