table already exists exception when migrate DB using Entity Framework Core and SQLite - sqlite

I'm using EF Core and SQLite in UWP. I tried to migrate by calling DbContext.Database.Migrate() but I always get Microsoft.Data.Sqlite.SqliteException: 'SQLite Error 1: 'table "Tags" already exists'.'.
I'm sure that the table doesn't exist because I checked on bin/debug folder, there is no database file. Even I check in wrong folder, there shouldn't have a problem doesn't it?
I've deleted Migrations folder many times but I don't think this is the cause of this exception.
This is DbContext code.
public class AppDbContext : DbContext
{
public DbSet<Word> Words { get; set; }
public DbSet<WordMeaning> WordMeanings { get; set; }
public DbSet<Tag> Tags { get; set; }
public DbSet<WordTag> WordTags { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Data Source=Vocabulary.db");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// PK declaration
modelBuilder.Entity<Word>()
.HasKey(w => w.Text);
modelBuilder.Entity<WordMeaning>()
.HasKey(wm => new { wm.WordText, wm.WordClass });
modelBuilder.Entity<Tag>()
.HasKey(t => t.Name);
modelBuilder.Entity<WordTag>()
.HasKey(wt => new { wt.WordText, wt.TagName });
// relation declaration
modelBuilder.Entity<Word>()
.HasMany(w => w.WordMeanings)
.WithOne(wm => wm.Word)
.HasForeignKey(wm => wm.WordText)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<WordTag>()
.HasOne(wt => wt.Tag)
.WithMany(t => t.WordTag)
.HasForeignKey(wt => wt.TagName);
modelBuilder.Entity<WordTag>()
.HasOne(wt => wt.Word)
.WithMany(w => w.WordTag)
.HasForeignKey(wt => wt.WordText);
}
}
and all of models code.
public class Tag
{
public string Name { get; set; }
public string Description { get; set; }
public List<WordTag> WordTag { get; set; }
}
public class Word
{
public string Text { get; set; }
public WordClass WordClasses { get; set; }
public DateTime AddedDate { get; set; }
public List<WordMeaning> WordMeanings { get; set; }
public List<WordTag> WordTag { get; set; }
}
public class WordMeaning
{
public string WordText { get; set; }
public string Definition { get; set; }
public string Example { get; set; }
public WordClass WordClass { get; set; }
public Word Word { get; set; }
}
public class WordTag
{
public Word Word { get; set; }
public Tag Tag { get; set; }
public string WordText { get; set; }
public string TagName { get; set; }
}

Do not use both EnsureCreated and Migrate, Only Migrate enough to create and migrate the DB
using (var db = new DBContext())
{
//db.Database.EnsureCreated(); Don't use
db.Database.Migrate();
}

#Gert Arnold said, Your SQLite database file (Vocabulary.db) should be created on the LocalFolder by default. You should be able to find the database with Tag table is already created on C:\Users\{username}\AppData\Local\Packages\{your app package name}\LocalState). The package name you can find by Package.appxmanifest->Packing->Package name on your project. More details about the file access on uwp app please reference Files, folders, and libraries.
And more details about entity framework with uwp please reference UWP - New Database.

Related

FK for composite key splitted into 2 when table with certain name is added

So I have the following entities defined.
internal class DeliveryArea
{
public string Postcode { get; set; }
public string State { get; set; }
public string Country { get; set; }
public ICollection<DeliveryPrice> HasDeliveryPrices { get; set; }
}
internal class DeliveryPrice
{
public uint Id { get; set; }
public DeliveryArea ForDeliveryArea { get; set; }
public string DeliveryAreaPostcode { get; set; }
public string DeliveryAreaState { get; set; }
public string DeliveryAreaCountry { get; set; }
}
and my DbContext is as follow
internal class MyDbContext : DbContext
{
// DbSets.
public DbSet<DeliveryArea> DeliveryAreas { get; set; }
public DbSet<DeliveryPrice> DeliveryPrices { get; set; }
// Overrides.
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite(#"Data Source=Test.EFCore.db;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
#region DeliveryArea.
{
var entity = modelBuilder.Entity<DeliveryArea>();
// Setup case-insensitive columns.
entity.Property(i => i.Postcode).HasColumnType("TEXT COLLATE NOCASE");
entity.Property(i => i.State).HasColumnType("TEXT COLLATE NOCASE");
entity.Property(i => i.Country).HasColumnType("TEXT COLLATE NOCASE");
// Setup composite PK.
entity.HasKey(nameof(DeliveryArea.Postcode), nameof(DeliveryArea.State), nameof(DeliveryArea.Country));
}
#endregion
#region DeliveryPrice.
{
var entity = modelBuilder.Entity<DeliveryPrice>();
// DeliveryPrice x DeliveryArea | many-to-one
entity.HasOne(left => left.ForDeliveryArea)
.WithMany(right => right.HasDeliveryPrices)
.HasForeignKey(left => new { left.DeliveryAreaPostcode, left.DeliveryAreaState, left.DeliveryAreaCountry });
}
#endregion
}
}
When the database is generated, EF Core manage to generate appropriate FK that connects both table using the composite key. Everything looks fine and the diagram looks great.
Now, I added the following entity
internal class Currency
{
public uint Id { get; set; }
public ICollection<DeliveryPrice> ForDeliveryPrices { get; set; }
}
and updated DeliveryPrice class as follow
internal class DeliveryPrice
{
public uint Id { get; set; }
// Add the following
public Currency HasCurrency { get; set; }
public uint HasCurrencyId { get; set; }
public DeliveryArea ForDeliveryArea { get; set; }
public string DeliveryAreaPostcode { get; set; }
public string DeliveryAreaState { get; set; }
public string DeliveryAreaCountry { get; set; }
}
My DbContext is updated on top of existing, as follow
internal class MyDbContext : DbContext
{
// DbSets.
public DbSet<Currency> Currencies { get; set; }
// Existing codes remain...
// Overrides.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
#region Currency.
{
var entity = modelBuilder.Entity<Currency>();
// Currency x DeliveryPrice | one-to-many
entity.HasMany(left => left.ForDeliveryPrices)
.WithOne(right => right.HasCurrency)
.HasForeignKey(right => right.HasCurrencyId);
}
#endregion
// Existing codes remain...
}
}
When the new database is generated, the FK that connects both DeliveryArea and DeliveryPrice table is kinda splitted into 2, as follow
The funny thing is that when the Currencies table is renamed to, say Foo, the FK that connects both DeliveryArea and DeliveryPrice table looks OK.
UPDATE 01:
Normal looking FK
Here's a screenshot of the generated FK that splitted into 2
UPDATE 02:
Upon looking further into the issue, I've found that this is specific to DBeaver only. Viewing the same database file with other database viewer (e.g. DbSchema) does not have the issue.
Any idea what's going on?

Many-to-Many Relation only includes one Entity [duplicate]

This question already has an answer here:
Many to many relationship mapping in EF Core
(1 answer)
Closed 3 years ago.
Dotnet Core 2.2, EntityFrameworkCore 2.2.3
In a Many-to-Many relation between the entities "Post" and "Category" the linked Entity "PostCategory" returns the "Post" object but for the "Category" object only the Id and not the object itself.
Migrations and database update works fine and all three tables are created.
For the relation itself I tried it with EF "auto magic" and explicit definition of the relation in OnModelCreating in the ApplicationDbContext.
Models
Post-Model
public class Post
{
public int Id { get; set; }
public string Slug { get; set; }
public string Title { get; set; }
public string Abstract { get; set; }
public string Content { get; set; }
public string Author { get; set; }
public DateTime Created { get; set; }
public ICollection<PostCategory> PostCategories { get; set; }
}
Category-Model
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<PostCategory> PostCategories { get; set; }
}
PostCategory Model
public class PostCategory
{
public int PostId { get; set; }
public Post Post { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
}
DbSets in ApplicationDbContext
public DbSet<Post> BlogPosts { get; set; }
public DbSet<Category> BlogCategories { get; set; }
public DbSet<PostCategory> PostCategories { get; set; }
Get all Posts from Service
public IEnumerable<Post> GetAll()
{
var posts = _context.BlogPosts
.Include(x => x.PostCategories);
return posts;
}
Calling service from Controller
public IActionResult Index()
{
var blogPosts2 = _blogService.GetAll();
...
}
The result is seen in the screenshot.
In ApplicationDbContext I tried two versions:
Version 1:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<PostCategory>()
.HasKey(x => new { x.PostId, x.CategoryId });
}
public DbSet<Post> BlogPosts { get; set; }
public DbSet<Category> BlogCategories { get; set; }
public DbSet<PostCategory> PostCategories { get; set; }
Version 2:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<PostCategory>()
.HasKey(x => new { x.PostId, x.CategoryId });
builder.Entity<PostCategory>()
.HasOne(pt => pt.Post)
.WithMany(p => p.PostCategories)
.HasForeignKey(pt => pt.PostId);
builder.Entity<PostCategory>()
.HasOne(pt => pt.Category)
.WithMany(t => t.PostCategories)
.HasForeignKey(pt => pt.CategoryId); ;
}
public DbSet<Post> BlogPosts { get; set; }
public DbSet<Category> BlogCategories { get; set; }
public DbSet<PostCategory> PostCategories { get; set; }
Both version migrate and update with no errors and the same result.
I'm grateful for any help.
Best regards
Edit:
I tried the "ThenInclude" before but obviously my Visual Studio auto completion has a problem:
If I ignore the auto completion, then it works, thank you!
To eager load related data in multiple level, you have to use .ThenInclude as follows:
public IEnumerable<Post> GetAll()
{
var posts = _context.BlogPosts
.Include(x => x.PostCategories)
.ThenInclude(pc => pc.Category);
return posts;
}
Here is the more details: Loading Related Data: Including multiple levels

AutoMapper - Cannot map between IdentityUser subclass and its correspondant DTO

I'm working on a project with asp.net core and Identity,
I am trying to create a mapping configuration between IdentityUser subclasse and its correspondant DTO using Automapper
I have done similar configuration with other classes and it works fine, but with IdentityUser subclass it behaves differently :
Here is my IdentityUser subclasse :
public partial class Collaborateur : IdentityUser
{
public Collaborateur() : base()
{
this.Activites = new HashSet<ActiviteCollaborateur>();
this.ActeursAvantVente = new HashSet<ActeurAvv>();
}
public string Nom { get; set; }
public string Prenom { get; set; }
public string Telephone { get; set; }
public Nullable<long> Matricule { get; set; }
public string Structure { get; set; }
public string Login { get; set; }
public RoleEnum Role { get; set; }
public virtual ICollection<ActiviteCollaborateur> Activites { get; set; }
public virtual ICollection<ActeurAvv> ActeursAvantVente { get; set; }
public virtual Agence Agence { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime LastModified { get; set; }
}
Its corresponding DTO :
public class CollaborateurDTO : BaseDTO
{
public string Nom { get; set; }
public string Prenom { get; set; }
public string Telephone { get; set; }
public Nullable<long> Matricule { get; set; }
public string Structure { get; set; }
public string Login { get; set; }
public RoleEnum Role { get; set; }
}
CollaborateurProfile config class :
public class CollaborateurProfile : Profile
{
CollaborateurProfile()
{
CreateMap<Collaborateur, CollaborateurDTO>().ReverseMap();
CreateMap<Collaborateur, Collaborateur>()
.ForMember(x => x.Id, opt => opt.Ignore())
.ForMember(x => x.CreatedAt, opt => opt.Ignore())
.ForMember(x => x.LastModified, opts => opts.MapFrom(src => DateTime.UtcNow));
}
}
and Startup.cs :
services.AddAutoMapper();
it stops at this line with
MissingMethodException was unhandled by user code
An exception of type 'System.MissingMethodException' occurred in System.Private.CoreLib.ni.dll but was not handled in user code
By mistake i answered this question at the question linked in the comments (https://stackoverflow.com/a/46567611/7131186)
Here is my answer:
In my case (and it seems that this is your case too) it was a copy/paste problem. I somehow ended up with a PRIVATE constructor for my mapping profile:
using AutoMapper;
namespace Your.Namespace
{
public class MappingProfile : Profile
{
MappingProfile()
{
CreateMap<Animal, AnimalDto>();
}
}
}
(take note of the missing "public" in front of the ctor)
which compiled perfectly fine, but when AutoMapper tries to instantiate the profile it can't (of course!) find the constructor!

Many to many relation between Identity and custom table. EF7 - Code first

How can I make many to many relation between AspNetRoles from Identity 3.0 and my custom table? I want simple 3 table, with both PermissionId and RoleId, something like AspNetUsersRole. I have something like this:
public class Permission
{
public int PermissionId { get; set; }
public string Name { get; set; }
public virtual ICollection<ApplicationRole> Roles { get; set; }
}
public class ApplicationRole : IdentityRole
{
public virtual ICollection<Permission> Permissions { get; set; }
}
But when I want to add migration, I got error:
Unable to determine the relationship represented by navigation property 'ApplicationRole.Permissions' of type 'ICollection<Permission>'. Either manually configure the relationship, or ignore this property from the model.
EF Core (EF7) does not currently support many to many relationship without a join entity. (Reference)
So, what you should do is to create an entity class for the join table and mapping two separate one-to-many relationships. Like;
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<PostTag>()
.HasKey(t => new { t.PostId, t.TagId });
modelBuilder.Entity<PostTag>()
.HasOne(pt => pt.Post)
.WithMany(p => p.PostTags)
.HasForeignKey(pt => pt.PostId);
modelBuilder.Entity<PostTag>()
.HasOne(pt => pt.Tag)
.WithMany(t => t.PostTags)
.HasForeignKey(pt => pt.TagId);
}
public class PostTag
{
public int PostId { get; set; }
public Post Post { get; set; }
public string TagId { get; set; }
public Tag Tag { get; set; }
}
Regarding to this question answer, it can be done more easily like this-
class Photo
{
public int Id { get; set; }
public ICollection<PersonPhoto> PersonPhotos{ get; set; }
}
class PersonPhoto
{
public int PhotoId { get; set; }
public Photo Photo { get; set; }
public int PersonId { get; set; }
public Person Person { get; set; }
}
class Person
{
public int Id { get; set; }
public ICollection<PersonPhoto> PersonPhotos{ get; set; }
}
Be sure to configure PersonPhoto with a composite key:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<PersonPhoto>().HasKey(x => new { x.PhotoId, x.PersonId });
}
To navigate, use a Select:
// person.Photos
var photos = person.PersonPhotos.Select(c => c.Photo);
Add This namespace-
using Microsoft.AspNetCore.Identity;
public class Permission
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int PermissionId { get; set; }
public string Name { get; set; }
public string UserIdFK { get; set; } //Foreign Key of Identity tbl
[ForeignKey("UserIdFK")]
public IdentityUser UserDetail { get; set; }
}
That's it, Happy coding :)

Code-first database mapping, table missing (wasn't created) for many-to-many relationship

I am building ASP.NET webforms application using Entity Framework 6.1, with code-first approach to generate database. I have two tables, Product and Tags, in many-to-many relationship. Classes are below:
public class Product
{
public long Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
}
public class Tag
{
public long Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products{ get; set; }
}
I want two junction tables out of this relationship ProductTags and ProductTagsTradeFor. So I overrided OnModelCreating of WebsiteDbContext.
modelBuilder.Entity<Product>().HasMany<Tag>(s => s.Tags).WithMany(c => c.Products)
.Map(cs =>
{
cs.MapLeftKey("ProductId");
cs.MapRightKey("TagId");
cs.ToTable("ProductTags");
});
modelBuilder.Entity<Product>().HasMany<Tag>(s => s.Tags).WithMany(c => c.Products)
.Map(cs =>
{
cs.MapLeftKey("ProductId");
cs.MapRightKey("TagId");
cs.ToTable("ProductTradeForTags");
});
After running the application, database was created and table ProductTradeForTags is present but table ProductTags was missing.
What is the problem and how do I fix it so both tables are created?
You can't share the navigation properties. You will need to add a second set of navigation collections to each:
public class Product
{
public long Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
public virtual ICollection<Tag> TradeForTags { get; set; }
}
public class Tag
{
public long Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Product> Products{ get; set; }
public virtual ICollection<Product> TradeForProducts{ get; set; }
}
Then
modelBuilder.Entity<Product>().HasMany(s => s.Tags).WithMany(c => c.Products)
.Map(cs =>
{
cs.MapLeftKey("ProductId");
cs.MapRightKey("TagId");
cs.ToTable("ProductTags");
});
modelBuilder.Entity<Product>().HasMany(s => s.TradeForTags).WithMany(c => c.TradeForProducts)
.Map(cs =>
{
cs.MapLeftKey("ProductId");
cs.MapRightKey("TagId");
cs.ToTable("ProductTradeForTags");
});
Your model require to navigate from a Tag to Products and from a Product to Tags.
In this case one association table is enough.
EF should raise an exception but it simply ignores the first configuration.

Resources