C
C#2mo ago
Ruttie

duplicate key error efcore

I'm trying to use efcore but I'm getting a duplicate key value violates unique constraint "PK_Tags" error. My model contains:
[Required]
public List<string> Tags { get; set; } = [];
[Required]
public List<string> Tags { get; set; } = [];
however, this is not a key? I'm updating the value by getting it from the database, modifying it, then calling Update with the modified value.
16 Replies
Keswiik
Keswiik2mo ago
Check your database schema. My guess is that Tags is being mapped to a new table.
Ruttie
Ruttie2mo ago
Is keeping entries I got from the database around for a long time bad? long time as in across dbcontexts in other words, if I get value a from dbctx1, then cache a, dispose of dbctx1, create dbctx2, and use the .Update method on dbctx2 with value a I'm guessing it is a problem, and that the changetracker of dbctx2 doesn't recognize a as being modified, rather created if that's the case, am I supposed to do a new query everytime I use a new dbcontext? isn't that inefficient? ping for visibility
Keswiik
Keswiik2mo ago
First off, did you look at your DB schema?
Ruttie
Ruttie2mo ago
I've come to the conclusion that this is most likely unrelated
Keswiik
Keswiik2mo ago
And you can keep entries around for a long time, I have caches like that in some of my projects. Not sure whether or not that's recommended, though.
Ruttie
Ruttie2mo ago
the sql states an INSERT INTO instead of the UPDATE I expect when using .Update
Keswiik
Keswiik2mo ago
show actual code
Ruttie
Ruttie2mo ago
I have a service injecting an IMemoryCache, then have a get method:
public DbTag? GetTag(ulong guildid, string name)
{
var key = new TagKey(guildid, name);
if (cache.TryGetValue(key, out DbTag? tag))
return tag!;
var guild = guilds.GetOrCreateGuild(guildid);
if (!guild.Tags.Contains(name))
return null;
var val = db.Tags.Find(guildid, name);
cache.CreateEntry(key).SetValue(val).SetAbsoluteExpiration(TimeSpan.FromMinutes(30)).Dispose();
return val;
}
public DbTag? GetTag(ulong guildid, string name)
{
var key = new TagKey(guildid, name);
if (cache.TryGetValue(key, out DbTag? tag))
return tag!;
var guild = guilds.GetOrCreateGuild(guildid);
if (!guild.Tags.Contains(name))
return null;
var val = db.Tags.Find(guildid, name);
cache.CreateEntry(key).SetValue(val).SetAbsoluteExpiration(TimeSpan.FromMinutes(30)).Dispose();
return val;
}
after which a second call to this gets the value from cache instead of db, and then I call this:
public void Update(ulong guild, DbTag value)
{
db.Tags.Update(value);
db.SaveChanges();
}
public void Update(ulong guild, DbTag value)
{
db.Tags.Update(value);
db.SaveChanges();
}
on the second context which then causes an error
Keswiik
Keswiik2mo ago
Show the code that calls Update
Ruttie
Ruttie2mo ago
if (tags.GetTag(guildid.Value, state) is not { } tag)
return (Result)await feedback.SendContextualAsync("This tag does not exist! (did someone delete the tag before you could update it?)", ct: base.CancellationToken);
tag.Content = content;
tag.IsEmbed = true;
tags.Update(guildid.Value, tag);
if (tags.GetTag(guildid.Value, state) is not { } tag)
return (Result)await feedback.SendContextualAsync("This tag does not exist! (did someone delete the tag before you could update it?)", ct: base.CancellationToken);
tag.Content = content;
tag.IsEmbed = true;
tags.Update(guildid.Value, tag);
I wonder if db.Tags.Update(value).State = Microsoft.EntityFrameworkCore.EntityState.Modified; would work
Keswiik
Keswiik2mo ago
You could also try tracking the entity before modifying it
Ruttie
Ruttie2mo ago
is there a way to make it track something?
Keswiik
Keswiik2mo ago
That's what DbSet.Update does it begins tracking an entity and sets the state to modified So I'd try calling DbSet.Update with your tag, modify the tag after, then call SaveChanges
Ruttie
Ruttie2mo ago
I was wondering if I could start tracking if I can get it from the cache
Keswiik
Keswiik2mo ago
So call DbSet.Update on your tags every time you load from the cache....?
Ruttie
Ruttie2mo ago
but it's never modified so I was concerned the setting state to modified would break things found .Attach seems to do that did not work got it working I was being stupid thanks for dealing with it :catlaugh: