c# - Entity Framework relationships between different DbContext and different schemas -
so, have 2 main objects, member , guild. 1 member can own guild , 1 guild can have multiple members.
i have members class in separate dbcontext , separate class library. plan reuse class library in multiple projects , differentiate, set database schema "acc". have tested library extensively , can add, delete, , update members in acc.members table.
the guild class such:
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; } }
with mapping of:
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"); }); } }
but, when try create new guild, says there no dbo.members.
i got reference member's ef project , added mapping members class dbcontext guild class part of. modelbuilder.configurations.add(new membermapping());
(not sure if best way.)
this resulted error:
{"the member identity 'guildproj.data.ef.guild_members' not exist in metadata collection.\r\nparameter name: identity"}
how can utilize foreign key between these 2 tables cross dbcontexts , different database schemas?
update
i narrowed down cause of error. when create new guild, set guild leader's member id memberid. works fine. but, when try add leader's member object guild's list of members (members), that's causes error.
update 2
here code of how create context guild class in. (as requested 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; } }
this how saving in 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(); } }
final resolution
so, had add mappings member
, role
, , permission
in dbcontext contained guild
. had add role , permission because member had list<role> roles
, each role had list<permission> permissions
.
this got me closer solution. still getting errors like:
{"the member identity 'guildproj.data.ef.member_roles' not exist in metadata collection.\r\nparameter name: identity"}
here, when pull member session
, this:
system.data.entity.dynamicproxies.member_ff4fde3888b129e1538b25850a445893d7c49f878d3cd40103ba1a4813eb514c
entity framework not seem play this. why? not sure, think because contextm creates proxy of member , cloning member new member object, contextm no longer has association. this, think, allows contextg use new member object freely. tried setting proxycreationenabled = false in dbcontexts, member object being pulled out of session kept being of type system.data.entity.dynamicproxies.member.
so, did was:
member member = new member((member)session[constants.usersession]);
i had clone each role
, each permission
inside respective constructors.
this got me 99% of way there. had alter repo , how saving guild
object.
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();
this working code:
in assembly "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(); } }
in assemby "g":
- your
guild
class - your
guild
mapping, albeitwillcascadeondelete(false)
inleadermemberinfo
mapping. modelbuilder.configurations.add(new guildmapping());
,modelbuilder.configurations.add(new membermapping());
code:
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();
executed sql:
insert [dbo].[members]([name]) values (@0) select [id] [dbo].[members] @@rowcount > 0 , [id] = scope_identity() -- @0: 'leader' (type = string, size = -1) insert [dbo].[guilds]([memberid], [name]) values (@0, @1) select [id] [dbo].[guilds] @@rowcount > 0 , [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] [dbo].[members] @@rowcount > 0 , [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)
this works when associating existing objects.
original answer more general case:
you can't combine types in different contexts 1 object graph. means, can't like
from in context.as join b in context.bs on ...
...because there's 1 context should create whole sql query, should have required mapping information.
you can register same type 2 different contexts though, different assemblies. map member
in context in guild
's assembly, let's call contextg
, if
member
doesn't refer other types aren't mapped incontextg
. may imply navigation properties inmember
must ignored explicitly.member
can't refer types incontextg
, because these types not part ofmember
's context.
if of these conditions can't fulfilled best can create new member
class in guild
's assembly , register mapping in context. maybe want use different name prevent ambiguity, alternative left.
Comments
Post a Comment