C# 不同DbContext和不同模式之间的实体框架关系

C# 不同DbContext和不同模式之间的实体框架关系,c#,entity-framework,foreign-keys,repository,dbcontext,C#,Entity Framework,Foreign Keys,Repository,Dbcontext,所以,我有两个主要的目标,会员和公会。一个成员可以拥有一个公会,一个公会可以有多个成员 我将Members类放在单独的DbContext和单独的类库中。我计划在多个项目中重用这个类库,为了帮助区分,我将数据库模式设置为“acc”。我已经对这个库进行了广泛的测试,可以在acc.Members表中添加、删除和更新成员 公会职业是这样的: public class Guild { public Guild() { Members = new List<Member

所以,我有两个主要的目标,会员和公会。一个成员可以拥有一个公会,一个公会可以有多个成员

我将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; }
}
如何利用这两个表之间的外键跨DBContext并使用不同的数据库模式

更新

我缩小了错误的原因。当我创建一个新公会时,我将公会领袖的成员ID设置为MemberID。这个很好用。但是,当我尝试将该领袖的成员对象添加到公会的成员列表时,这就是导致错误的原因

更新2

下面是我如何创建公会类所在上下文的代码。(应侯赛因·哈利勒的要求)

最终决议

因此,我必须在包含
Guild
的DbContext中添加到
成员
角色
权限
的映射。我必须添加角色和权限,因为成员有
列表角色
,每个角色都有
列表权限

这让我更接近解决方案。我仍然会遇到如下错误:

{"The member with identity 'GuildProj.Data.EF.Member_Roles' does not exist in the metadata collection.\r\nParameter name: identity"}
在这里,当您从
会话
中提取成员时,您会得到如下结果:

System.Data.Entity.DynamicProxies.Member_FF4FDE3888B129E1538B25850A445893D7C49F878D3CD40103BA1A4813EB514C
实体框架似乎不能很好地处理这个问题。为什么?我不确定,但我认为这是因为ContextM创建了一个成员的代理,并且通过将成员克隆到一个新的成员对象中,ContextM不再具有关联。我认为,这允许ContextG自由地使用新成员对象。我尝试在DbContext中设置ProxyCreationEnabled=false,但从会话中拉出的成员对象的类型仍然是System.Data.Entity.DynamicProxies.Member

所以,我所做的是:

Member member = new Member((Member)Session[Constants.UserSession]);
我必须克隆每个
角色
和每个
权限
以及它们各自的构造函数

这让我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();

我发现,当我在实体和构建关系方面遇到问题时,通常是因为我违背了框架的流程,或者试图构建技术上不完善的关系或抽象。我在这里的建议是,在深入研究这个具体问题之前,快速后退一步,分析一些事情

首先,我很好奇为什么您在这里使用不同的模式来处理可能是单个应用程序访问对象图的情况。在某些情况下,多个模式可能很有用,但我认为Brent Ozar在这方面提出了一个非常突出的观点。考虑到这些信息,我倾向于首先建议您将多个模式合并为一个模式,然后再使用单个数据库上下文

接下来要处理的是对象图。至少对我来说,我在数据建模方面遇到的最大困难是我没有首先弄清楚应用程序对数据库有什么问题。我的意思是,首先要弄清楚应用程序在各种上下文中需要什么样的数据,然后看看如何在关系上下文中优化这些数据结构以提高性能。让我们看看如何做到这一点

根据您的上述模型,我可以看出我们在该领域有几个关键术语/对象:

  • 公会收藏
  • 成员集合
  • 帮会领袖的集合
此外,我们还有一些需要实施的业务规则:

  • 一个公会可以有一个领袖(可能不止一个?)
  • 帮主必须是会员
  • 公会有0个或更多成员的列表
  • 一个成员可以属于一个公会(可能不止一个?)
因此,根据这些信息,让我们调查一下您的应用程序可能对这个数据模型有哪些问题。I申请书可以:

  • 查找成员并查看其属性
  • 查找成员并查看他们的属性以及他们是否是帮会领袖
  • 查找公会并查看其所有成员的列表
  • 查找一个公会并查看公会领袖的列表
  • 查找所有帮会领袖的列表
好了,现在我们可以开始讨论黄铜大头钉了,就像他们说的

在这种情况下,在公会和会员之间使用联接表是最佳的。它将为您提供在多个公会或无公会中拥有会员的能力,并提供低锁定更新策略-非常好的呼叫

至于工会领袖,有几个选择可能是有意义的。尽管从来没有一个例子可以说是行会士官,但我认为考虑一个新的实体叫做工会领袖是有意义的。这种方法的好处是多方面的。你可以在应用程序中缓存帮会领袖id列表,这样你就可以访问只有领袖id列表而不是整个领袖对象的本地应用程序缓存,而不是通过数据库访问来授权领袖采取的帮会行动;相反,您可以获得工会的领导列表,无论查询方向如何,您都可以点击核心实体上的聚集索引或加入实体上易于维护的中间索引


正如我在“答案”的开头所指出的,当我遇到像你这样的问题时,通常是因为我违背了实体的本质。我鼓励您重新思考您的数据模型以及如何使用较低摩擦的方法—松开多模式并添加一个中间的guild_leader对象。干杯

除非您明确表示,
成员
实体应映射到
acc.Members
,否则EF将希望它位于
dbo中
{"The member with identity 'GuildProj.Data.EF.Member_Roles' does not exist in the metadata collection.\r\nParameter name: identity"}
System.Data.Entity.DynamicProxies.Member_FF4FDE3888B129E1538B25850A445893D7C49F878D3CD40103BA1A4813EB514C
Member member = new Member((Member)Session[Constants.UserSession]);
            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();
public class Member
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class MemberMapping : EntityTypeConfiguration<Member>
{
    public MemberMapping()
    {
        this.HasKey(m => m.Id);
        this.Property(m => m.Name).IsRequired();
    }
}
var m = new Member { Name = "m1" };
var lm = new Member { Name = "leader" };
var g = new Guild { Name = "g1" };
g.LeaderMemberInfo = lm;
g.Members.Add(lm);
g.Members.Add(m);
c.Set<Guild>().Add(g);
c.SaveChanges();
from a in context.As
join b in context.Bs on ...
context.Entry(Guild.Members).State = Entity.EntityState.Unchanged