Итак, у меня есть два основных объекта: член и гильдия. Один член может владеть Гильдией, и у одной Гильдии может быть несколько Членов.Соотношения структуры Entity Framework между различными DbContext и различными схемами
У меня есть класс членов в отдельном 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-члена и добавил сопоставление классу-члену в 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 лидера к списку членов Гильдии (членов), это и вызывает ошибку.
UPDATE 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();
}
}
FINAL Решение
Итак, мне пришлось добавить сопоставления в 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
Entity 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();
Нельзя ли использовать тот же класс 'Member'? Отображение будет различным между контекстами, и объект 'Member' не сможет быть перенесен между контекстами, не будучи отделенным от первого, но это кажется возможным. – jjj
@jjj Да, но я предполагаю, что 'Member' будет иметь другие ассоциации, которые не должны отображаться. Если 'Member' является POCO, а отображения - свободным отображением, то это должно быть возможно, явно оставив свойства навигации без изменений. Но я думаю, что запутать объекты 'Member' в одном приложении, которые могут быть реализованы в разных контекстах. –
Не имеет значения, что свойство GuildLeader, которое из типа Member правильно сохраняет базу данных, но свойство List не работает. И только сохранение идентификатора. –
ScubaSteve