jjzjj

c# - 不同 DbContext 和不同模式之间的 Entity Framework 关系

coder 2024-05-20 原文

因此,我有两个主要对象,Member 和 Guild。一个成员(member)可以拥有一个公会,一个公会可以有多个成员(member)。

我在单独的 DbContext 和单独的类库中有 Members 类。我计划在多个项目中重用这个类库并帮助区分,我将数据库模式设置为“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。

我得到了对 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"}

我如何跨 DbContexts 和不同的数据库模式利用这两个表之间的外键?

更新

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

更新 2

这是我如何创建 Guild 类所在的 Context 的代码。(应 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; }
}

这就是我将它保存在 repo 中的方式:

    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在包含 Guild 的 DbContext 中.我必须添加角色和权限,因为成员有 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 中拉取 Member 时,你会得到这样的东西:

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以及在它们各自的构造函数中。

这让我完成了 99% 的工作。我不得不改变我的 repo 以及我如何保存 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();

最佳答案

这是工作代码:

在程序集“M”中:

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();
    }
}

在汇编“G”中:

  • 你的 Guild
  • 你的 Guild 映射,虽然在 LeaderMemberInfo 映射中有 WillCascadeOnDelete(false)
  • modelBuilder.Configurations.Add(new GuildMapping());modelBuilder.Configurations.Add(new MemberMapping());

代码:

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();

执行的SQL:

INSERT [dbo].[Members]([Name])
VALUES (@0)
SELECT [Id]
FROM [dbo].[Members]
WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity()
-- @0: 'leader' (Type = String, Size = -1)

INSERT [dbo].[Guilds]([MemberID], [Name])
VALUES (@0, @1)
SELECT [ID]
FROM [dbo].[Guilds]
WHERE @@ROWCOUNT > 0 AND [ID] = scope_identity()
-- @0: '1' (Type = Int32)
-- @1: 'g1' (Type = String, Size = -1)

INSERT [dbo].[GuildsMembers]([GuildID], [MemberID])
VALUES (@0, @1)
-- @0: '1' (Type = Int32)
-- @1: '1' (Type = Int32)

INSERT [dbo].[Members]([Name])
VALUES (@0)
SELECT [Id]
FROM [dbo].[Members]
WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity()
-- @0: 'm1' (Type = String, Size = -1)

INSERT [dbo].[GuildsMembers]([GuildID], [MemberID])
VALUES (@0, @1)
-- @0: '1' (Type = Int32)
-- @1: '2' (Type = Int32)

这在关联现有对象时也适用。


更一般情况的原始答案:

您不能将不同上下文中的类型组合到一个对象图中。这意味着,你不能做类似的事情

from a in context.As
join b in context.Bs on ...

...因为总有一个上下文应该创建整个 SQL 查询,所以它应该具有所有必需的映射信息。

不过,您可以将同一类型注册到两个不同的上下文中,甚至可以来自不同的程序集。所以你可以在 Guild 的程序集的上下文中映射 Member,我们称它为 contextG,但前提是

  1. Member 不引用 映射到 contextG 中的其他类型。这可能意味着必须明确忽略 Member 中的导航属性。
  2. Member 不能引用 contextG 中的类型,因为这些类型不是 Member 上下文的一部分。

如果这些条件中的任何一个不能满足,你能做的最好的事情就是在 Guild 的程序集中创建一个新的 Member 类,并在上下文中注册它的映射.也许您想使用不同的名称来避免歧义,但这是剩下的唯一选择。

关于c# - 不同 DbContext 和不同模式之间的 Entity Framework 关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30608266/

有关c# - 不同 DbContext 和不同模式之间的 Entity Framework 关系的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  4. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  5. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

    在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

  6. ruby-on-rails - `a ||= b` 和 `a = b if a.nil 之间的区别? - 2

    我正在检查一个Rails项目。在ERubyHTML模板页面上,我看到了这样几行:我不明白为什么不这样写:在这种情况下,||=和ifnil?有什么区别? 最佳答案 在这种特殊情况下没有区别,但可能是出于习惯。每当我看到nil?被使用时,它几乎总是使用不当。在Ruby中,很少有东西在逻辑上是假的,只有文字false和nil是。这意味着像if(!x.nil?)这样的代码几乎总是更好地表示为if(x)除非期望x可能是文字false。我会将其切换为||=false,因为它具有相同的结果,但这在很大程度上取决于偏好。唯一的缺点是赋值会在每次运行

  7. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  8. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  9. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  10. ruby - Rails 关联 - 同一个类的多个 has_one 关系 - 2

    我的问题的一个例子是体育游戏。一场体育比赛有两支球队,一支主队和一支客队。我的事件记录模型如下:classTeam"Team"has_one:away_team,:class_name=>"Team"end我希望能够通过游戏访问一个团队,例如:Game.find(1).home_team但我收到一个单元化常量错误:Game::team。谁能告诉我我做错了什么?谢谢, 最佳答案 如果Gamehas_one:team那么Rails假设您的teams表有一个game_id列。不过,您想要的是games表有一个team_id列,在这种情况下

随机推荐