asp.net Identity classes from Entity Framework - c#

Am I able to use Entity Framework models (Classes) as a classes for asp.net Identity
so the relations that I have in my database will be loaded when I retrieve the user and if I update any columns or add tables I only have to deal with Entity Framework model.
I did do my custom classes for users
public class MyUser : IdentityUser<long, MyLogin, MyUserRole, MyClaim>{ ... }
and connected it with the table
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<MyUser>().ToTable("Users");
.....
}
but I have more tables that are connected with 'Users' table that isn't with Identity model
for example:
I have a table called Person(Not really just an example)
and each person may have many users and each user may have many
persons
So We have another table called 'PersonsUsers'
So the user have a list
I don't want to call the database twice to retrieve a single user data, and mapping the table from code will make my code static and depends on me updating the source code.
so Is it possible to use the classes that EF generated for the tables?
Do you have any other solution?

Yes, this is possible. Your MyUser class could have a property with the list of Person. then in your modelBuilder, you set up the mappings. Something like this:
modelBuilder.Entity<MyUser>().HasMany(m => m.Person)
.WithMany(p => p.MyUser)
.Map(m => {
m.ToTable("PersonUsers");
m.MapLeftKey("MyUserID");
m.MapRightKey("PersonID");
I believe this will accomplish what you're looking for.

Related

Ways to map database with Entity Framework?

How many ways are there to map a database with Entity Framework in .NET?
I understand there is code-first and database-first (using .EDMX wizard for example).
Within the context of database-first, can I map my tables and relationships manually without using .EDMX? How many ways exist and which do you recommend?
Are there libraries for manual table mapping, which are the best?
I think there is not a best way, but maybe there is a way that fits best your needs.
I'll try to explain the ways you have, than you can choose the best for you.
On high level, there are two options:
DB first: you define the database and let a tool to create your model classes
Code first: you define your classes and let EF manage the tables for you
Mainly DB first is the best for:
Map an already existing database: in this situation your DB is already designed, so you have only to map entities
Your focus is the DB structure: in this situation, better if you design your DB as you want, then let a tool to map your entities
Code first is the best when you don't mind about the DB but you want to think about the object model. Of course, you can change how the DB is generated using data annotation or any other way EF gives you, but the focus for you has to be the object model.
Hi yes can can absolutely Map a database from EF. It is called scaffolding. What it does is it creates the database as models and required files for you.
Once you open the package manage or cmd you can type the following one-liner to scafford you database:
CMD:
dotnet ef dbcontext scaffold "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook" Microsoft.EntityFrameworkCore.SqlServer
Package Manager:
Scaffold-DbContext "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook" Microsoft.EntityFrameworkCore.SqlServer
See the EF Core tutorial on it on the official windows website:
https://learn.microsoft.com/en-us/ef/core/managing-schemas/scaffolding?tabs=dotnet-core-cli
And for EF6 there is a great tutorial right here:
https://www.illucit.com/en/asp-net/entity-framework-7-code-first-migrations/
For full manual control with a Database-First project you can leverage a combination of convention, attributes, and/or entity configurations to configure the entities. Scaffolding I find works 90% of the time, but usually there will be some aspect of a production schema, especially where you don't have the flexibility to change the schema to make it more ORM-friendly, that scaffolding doesn't quite handle.
Also, if you're adopting something like bounded contexts (think DbContexts with fit-for-purpose mappings) and want to customize how tables/views map to entities, then it helps to be more explicit with the mapping. For example, for general entities I will map navigation properties, but in cases where I want raw performance over larger operations I will want to forgo declaring navigation properties and work strictly with FK columns. The less "mapping" a DbContext has to worry about and fewer entities it is tracking, the faster it performs.
Attributes: Here you declare your entity classes and use the appropriate attributes to describe the table, key, and other aspects such as column renames etc.
I.e.
[Table("tblOrders", "App")] // tblOrders table in App namespace
public class Order
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int OrderId { get; set; }
[Column("OrderNum")]
public string OrderNumber { get; set; }
public string OrderRef { get; set; }
[ForeignKey("Customer")]
public int CustomerId { get; set; }
public virtual Customer Customer { get; set; }
}
This works for the 90-%ile of cases where you want to set up entities. For simple columns that you don't need to rename etc. you don't need to add attributes and leave it to convention.
Entity Configuration: The commonly referenced means of doing this is to use the DbContext's OnModelCreating override and use modelBuilder to configure the entities. For smaller system with a couple handfuls of entities this can be manageable, but for larger systems this can get rather bloated since everything ends up in one method, or a chain of method calls to break it up.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Order>()
.ToTable("tblOrders", "App")
.HasKey(x => x.OrderId)
.Property(x => x.OrderId)
.HasDatabaseGenerated(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Order>()
.Property(x => x.OrderNumber)
.HasColumnName("OrderNum);
modelBuilder.Entity<Order>()
.HasRequired(x => x.Customer)
.WithMany(x => x.Orders)
.HasForeignKey(x => x.CustomerId);
}
The lesser documented option is to leverage EntityTypeConfigration<TEntity> (IEntityTypeConfiguration<TEntity> in EF Core)
public class OrderConfiguration : EntityTypeConfiguration<Order>
{
public OrderConfiguration()
{
ToTable("tblOrders", "App");
HasKey(x => x.OrderId)
.Property(x => x.OrderId)
.HasDatabaseGenerated(DatabaseGeneratedOption.Identity);
Property(x => x.OrderNumber)
.HasColumnName("OrderNum");
HasRequired(x => x.Customer)
.WithMany(x => x.Orders)
.HasForeignKey(x => x.CustomerId);
}
}
From there the DbContext just needs to be initialized to load the entity type configurations. This is done in the OnModelCreating which you can do explicitly, or add all Configurations by assembly.
modelBuilder.Configurations.AddFromAssembly(GetType().Assembly);
Personally, I default to declaring EntityTypeConfigurations for all entities as I prefer to rely on convention as little as possible. Being explicit with the configuration means you have something to investigate and work with where a convention doesn't work the way you expect, and it allows you to declare mappings for things like ForeignKeys without declaring FK properties in the entities. (Highly recommended to avoid two sources of truth about a relationship, being the FK and the navigation property)
My projects will commonly have a .Data project where I will keep the Entities, DbContext, and Repositories for a project. The EntityTypeConfiguration instances I place under /Entities/Configuration. They could just as easily be housed in the entity class files, as internal members of the entity class itself, or nested under the Entity class. (I.e. using a plugin like NestIn)

How to map an entity for a table that already has a mapped entity and avoid EF conflicts?

I want to map a simplified read-only entity (e.g. for UI dropdowns, that need only id and name) to a table that already has full-feature entity mapped.
I have fairly typical mapping configurations using IEntityTypeConfiguration classes that map entities through EntityTypeBuilder<MyFullClass> and EntityTypeBuilder<MySimpleClass>.
I have no control over database, it's a legacy project and I cannot add new SQL views just to solve this code issue.
public class MyFullClassConfiguration : IEntityTypeConfiguration<MyFullClass>
{
public void Configure(EntityTypeBuilder<MyFullClass> builder)
{
builder.ToTable("MyTable");
... all properties mapped
public class MySimpleClassConfiguration : IEntityTypeConfiguration<MySimpleClass>
{
public void Configure(EntityTypeBuilder<MySimpleClass> builder)
{
builder.ToTable("MyTable");
... minimum of required properties mapped
When I run the project, I get an error:
Cannot use table 'MyTable' for entity type 'MySimpleClass' since it is being used for entity type 'MyFullClass' and there is no relationship between their primary keys.
I tried to artificially link both entities, adding one-to-one relation:
b.HasOne<MyFullClass>().WithOne().HasForeignKey<MySimpleClass>(e => e.Id);
This time the project was started normally, I could read and update entities, but when saving a new MyFullClass, EF threw:
The entity of type 'MyFullClass' is sharing the table 'MyTable' with entities of type 'MySimpleClass', but there is no entity of this type with the same key value that has been marked as 'Added'.
This seems so common scenario - to return simplified versions of complex entities for performance and bandwidth reasons, so I was surprised to discover that it's not supported in EF and that they will implement it only in v3, if I'm not mistaken: https://github.com/aspnet/EntityFrameworkCore/issues/15310
How do I solve this in .NET Core 2.2?

EF/Code First Migration - implicit table mappings?

I am using a code first migration approach to creating new tables in an existing database, and I'd like to know if this is auto-creating a property-to-field mapping somewhere in the project.
For example: the "Category" table pre-existed in the database. It was created directly in SQL, and my MCV project has a CategoryMap.cs file that explicitly maps the Category entity properties to the Category table fields:
CategoryMap.cs
this.ToTable("Category", "ctt");
this.Property(t => t.Id).HasColumnName("Id");
this.Property(t => t.ClientId).HasColumnName("ClientId");
this.Property(t => t.CategoryTypeId).HasColumnName("CategoryTypeId");
etc.
The db context class explicitly points to this mapping in the OnModelCreating method:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new CategoryMap());
etc.
With this set-up, I can save data to the Category table, as long as I keep the mapping pieces in place.
On the other hand, I've created a new table using the code first approach:
1) Create a "MyTable" entity class
2) Add this code to my context class:
public DbSet<MyTable> MyTable { get; set; }
3) Run the add-migration and update-database commands
That created a "MyTable" table in the database schema, and I can save data to this table, despite the fact that there is no mapping file, and no explicit mapping code in the OnModelCreating method of my db context class.
Now, if I comment out the "modelBuilder.Configurations.Add(new CategoryMap());" line of code in the context class, I can't save data to that table any more; I get a "table 'Category' not found" error message when I try to do db.SaveChanges().
So I guess my question is this: when I created "MyTable" using the add-migration and update-database commands, did a class-to-table map get auto-generated somewhere behind the scenes? If so, can I access it and view it?
There are no auto generated mappings as such but a number of mapping conventions that get applied if there are no specific mappings. For example if you have no explicit table mapping then by convention it will map to a table that matches the class name.
So for a class Category it will by convention map to a table called Category.
This is also true of properties so Property(t => t.Id).HasColumnName("Id"); doesn't actually do anything as the property will have that mapping by convention. You only need explicit mappings when you go outside the conventions. So if you wanted to map you property Id to a column called Category_id then you would need a column mapping Property(t => t.Id).HasColumnName("Category_id");
Read this MSDN article for more info on the default conventions.

Split ASP .Net Identity Entity across multiple tables

Is there a simple way to split ASP .Net Identity entities across multiple tables? I know you can change the name of the tables used by Identity using OnModelCreating.
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUser>().ToTable("IdentityUser").Property(p => p.Id).HasColumnName("UserId");
}
Can you similarly use an override in OnModelCreating or elsewhere to split across multiple tables? I tried using a map:
modelBuilder.Entity<IdentityUser>().Map(m =>
{
m.Properties(t => new {t.Id, t.UserName});
m.ToTable("User");
});
but I receive an error indicating UserName is already mapped. The non-key property 'UserName' is mapped more than once. Ensure the Properties method specifies each non-key property only once.
I assume this is due to the default mapping of Identity already having UserName mapped. Can I override this or remove the default mapping somehow in order to achieve splitting the IdentityUser entity across multiple tables?

Entity Framework Code First: Custom Mapping

public class User
{
public int Id {get;set;}
public string Name {get;set}
public ICollection<User> Followers {get;set;}
public ICollection<User> Following {get;set;}
}
My Model looks like above, Entity framework automatically creates A table and UserUser with rows User_ID and User_ID1 in DB to map this model. I want to map that table and rows myself.
How can i do that, Thanx!!
From Scott Gu's blog about Many-valued Associations:
Many-to-Many Associations
The association between Category and Item is a many-to-many
association, as can be seen in the above class diagram. a many-to-many
association mapping hides the intermediate association table from the
application, so you don’t end up with an unwanted entity in your
domain model. That said, In a real system, you may not have a
many-to-many association since my experience is that there is almost
always other information that must be attached to each link between
associated instances (such as the date and time when an item was added
to a category) and that the best way to represent this information is
via an intermediate association class (In EF, you can map the
association class as an entity and map two one-to-many associations
for either side.).
In a many-to-many relationship, the join table (or link table, as some
developers call it) has two columns: the foreign keys of the Category
and Item tables. The primary key is a composite of both columns. In EF
Code First, many-to-many associations mappings can be customized with
a fluent API code like this:
class ItemConfiguration : EntityTypeConfiguration<Item> {
internal ItemConfiguration()
{
this.HasMany(i => i.Categories)
.WithMany(c => c.Items)
.Map(mc =>
{
mc.MapLeftKey("ItemId");
mc.MapRightKey("CategoryId");
mc.ToTable("ItemCategory");
});
} }
Register this configuration in your DbContext's (you using the DbContext api right?) like this:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new ItemConfiguration());
}
Good luck, hope this help!
To map an entity to itself, you would do something like this
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().HasMany(u => u.Followers)
.WithMany().ForeignKey(u => u.FollowerId);
base.OnModelCreating(modelBuilder);
}
its hard to tell without seeing your database model though, and how you actually relate the followers to the user.

Categories

Resources