✅ Efcore help with 2 databases
I'm trying to add a config option for the user to be able to select between psql and SQLite, do I need 2 contexts for this? If so what would be the main differences between the two?
98 Replies
You don't need multiple contexts, but you might need two sets of migration in some cases
You can look at this for ideas on the topic: https://blog.jetbrains.com/dotnet/2022/08/24/entity-framework-core-and-multiple-database-providers/
poggers thx
you may need separate contexts/configurations depending on what provider specific features you use iirc
Yeah
You'll need to either use the lowest common denominator
Or make one context that uses SQLite, and one that takes full advantage of Postgres
Or... don't bother with SQLite
i briefly tried to add sqlite support to make local testing of my application simpler and it was way too much effort
docker gang
the application in question already supports sqlite, we are migrating to psql but want to give selfhosters the option to choose
Then either use two DbContexts, or forever be gimped by the limitations of SQLite
speaking of
Postgres is very simple to set up
I'd say just require postgres
and screw over existing selfhosts?
you would need a migration for existing users
now how would i fix the primary key issue
it seems the sequal gem did not transfer it
sequel
sequel gem?
yeah theres a ruby gem that lets you migrate dbs
pgloader didnt work
wait
why are we suddenly discussing Ruby now?
so
was just mentioning what i used to migrate
anyway thats unimportant
... ok
show your EF model class
one moment...
GitHub
Mewdeko/src/Mewdeko.Database/Models at main · SylveonDeko/Mewdeko
Mewdeko. Contribute to SylveonDeko/Mewdeko development by creating an account on GitHub.
this is the base class for every model and it clearly has a marked key
well you didn't derive from it here
public class GuildCurrency
oh a new class kekw
havent even made the migration for it yet
now to solve this
should be easier lel
i have run into my first issue with this...
or just remove yourself from the post instead of helping that works too.
so i have a different issue now
on boot, my bot loads a few things into memory, at the same time however because of psql it now takes even longer to boot because ive been needing to use tolist because of a tinput/toutput requires ienumerable error
pardon?
ok, one sec
for example, in a constructor i have these 2 lines:
var gc = uow.GuildConfigs.Include(x => x.NsfwBlacklistedTags).Where(x => client.Guilds.Select(socketGuild => socketGuild.Id).Contains(x.GuildId));
blacklistedTags = new ConcurrentDictionary<ulong, HashSet<string>>(
gc.ToDictionary(
x => x.GuildId,
x => new HashSet<string>(x.NsfwBlacklistedTags.Select(y => y.Tag))));
if i load them normally right now i get an error with psql
that i didnt have with sqlite
waiting for it to start one sec...
Exception has been thrown by the target of an invocation.
---> System.ArgumentException: Both TInput and TOutput must be IEnumerable
it gives me that.
now when i add the tolist, it fixes it, but causes massive performance issues.
that's way too much to be happening in a constructor, plus it prevents you from taking advantage of async
tru, a lot of the bot needs to be refactored
but
well, we need the full error to do much
sec
beeg error
that error looks like it's from a completely different part of your code
Mewdeko.Modules.Administration.Services.GuildTimezoneService..ctor
it has the same thing, tolist
but
cant i just use asenumerable?
i kinda forgot that exists.
that will force client-side enumeration
hmm
that is, EF will be forced to execute your query, pulling everything into memory
so
not much better than tolist
at all
so heres the thing,
on boot, it sorts a few things for each service/module in a dictionary or concurrenthashset
even concurrentdictionary at times
psql doesnt like that, but i had no issues on sqlite
so im at a bit of a loss at what to do
i don't know how much EF Core likes this being in the where expression itself
client.Guilds.Select(socketGuild => socketGuild.Id).Contains(x.GuildId)
i'm going to guess something in there is causing problems since the rest should be getting evaluated client side based on what's on your github
maybe try turning the client's guild IDs into a list first?Would that really cause an issue?
.... My bot is in 10k guilds
idk, that's just my suggestion for something to try
Obviously not testing on production but
well it's in 0 if it doesn't work
Production is in 10k guilds
okay, use an array pool in prod
Alright
is this bot sharded? 10k seems steep for a single instance
It is ofc
5 shards
Right now I'm testing a local db/program copy
so this:
Gives the same error
understandable because that code is not related to the error you shared
It is, it gives the same error
same stack trace, just different location
nvm, reading hard
Lol
Happens
well, based on github
GetTimeZoneTuple
is not a function that can be translated to SQL
still not directly related to your error, but it shouldn't work
TimeZoneInfo.FindSystemTimeZoneById
doesn't have a translation according to https://www.npgsql.org/efcore/mapping/translations.htmlhmm
so what do i do
dunno, i'm surprised it's not complaining about a translation failure before getting to this point
same
its actually complaining in my concurrenthashset class now
i mean
the other option is raw queries
lmao
maybe
i dont see any other option that wont kill startup times
ultimately something in your query isn't translating correctly, but i don't know enough about ef/npgsql internals to know exactly
hmm oof
simple
tho i may have to do "" around the table/column names because psql
i'm gonna sql inject your guild
lel
perfect
.... not perfect
im getting a formatting error
love it
god fucking damn it
same error
enumerable anyone at all shed some light?
ive been at this since 12am yesterday
i really want to avoid using tolist
help. i really want to avoid doing this.
Why do you not want an IEnumerable?
because doing tolist or doing asenumerable caches it
this works fine on sqlite
var gc = uow.GuildConfigs.Include(x => x.NsfwBlacklistedTags).Where(x => client.Guilds.Select(socketGuild => socketGuild.Id).Contains(x.GuildId));
blacklistedTags = new ConcurrentDictionary<ulong, HashSet<string>>(
gc.ToDictionary(
x => x.GuildId,
x => new HashSet<string>(x.NsfwBlacklistedTags.Select(y => y.Tag))));
why is pgsql any different??
sqlite, the database where you cant even change the primary key
So why, then, you say you want to avoid
.ToList()
as well...?tell me why loading 20k records into memory is bad?
It takes a lot of memory
and a lot of startup time
So you don't want an enumerable, you don't want a list...
it was working with sqlite
there has to be something that we are not seeig here
Lemme format your code properly first so I can actually see what's going on there
sec
same thing, works with sqlite
throws the same error with postgres
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> System.ArgumentException: Both TInput and TOutput must be IEnumerable
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.ValueConversion.NpgsqlArrayConverter`2
What's
GetTimezoneTuple
?
but i think thats irrelavant because it has the same error with todictionary
Yeah, well, no chance in hell this will translate to SQL
I mean, it worked in SQLite
Lol
Maybe the SQLite driver does the untranslatable things on the client by default
.... so it passes when i remove the where with the guildid
but not with.
sorry the contains
wat
Whats wrong here?
so the solution was to use:
or at least so far thats the solutuon
something is very wrong here.
i went from 15 seconds load time to a whole 2 minutes.
uh
Was this issue resolved? If so, run
/close
- otherwise I will mark this as stale and this post will be archived until there is new activity.