How do I tell UserManager.FindByNameAsync to include a relation? - entity-framework

I am using ASP.NET Identity 2.2.0 with ASP.NET MVC 5.2.3 and Entity Framework 6.1.2.
I added a new property and its corresponding table to my database using ASP.NET Identity with Code First like so:
public class ApplicationUser
{
[ForeignKey("UserTypeId")]
public UserType Type { get; set;}
public int UserTypeId { get; set;}
}
public class UserType
{
[Key]
public int Id { get; set;}
public string Name { get; set; }
}
Now, from some action, when I call:
var user = UserManager.FindByNameAsync(userName);
It does get the user with the correct UserTypeId because that is a primitive, but it does not get the UserType property of the ApplicationUser class.
If I were not using this abstraction, I would either call LoadProperty<T> or the Include method in Entity Framework to include the navigational property or relation named Type (of type UserType) on the ApplicationUser class.
How do I do that with ASP.NET Identity's UserManager? I suspect the only way would be to override this method in my custom UserManager derived class and do it myself?

With Entity Framework lazy loading, you need to ensure that your navigation properties are marked as virtual.
public class ApplicationUser
{
[ForeignKey("UserTypeId")]
public virtual UserType Type { get; set;}
public int UserTypeId { get; set;}
}
Alternatively if you are unable/don't want to use lazy loading, then you can still use your context as you would any other entity:
var user = context.Users.Include(u => u.Type).Single(u => u.UserName == userName);

Related

Entity Framework Core - retrieve entire DbSet without using include()

Let's say I have the following 2 classes that will represent a relationship between 2 DB Tables (created using EF Core Migrations):
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
public Book Book { get; set; }
}
public class Book
{
public int Id { get; set; }
public String name { get; set; }
public string Genre { get; set; }
}
These 2 classes are added in as a DbSet in my ApplicationDbContext class.
When I retrieve the Author record, I want the Book object to also be populated info. It seems I have to retrieve it in the following way:
return _context.Author.Include(x => x.Book).ToList();
If I had a dozen of different objects in the Author class does that mean I have to chain the .Include() method calls for each object? Is there a catch-all method that will tell me to populate all of the objects inside the Author class? Something like .IncludeAll() perhaps?
You can use lazy loading enabled on your EF core. This way you don't need to include it every time.
Basically you need to add virtual keyword to your book entity:
public class Author{
public int Id {get; set;}
public string Name {get; set; }
public virtual Book Book {get; set; }
}
public class Book {
public int Id {get; set;}
public String name {get; set;}
public string Genre {get; set; }
}
Then you need to enable lazy loading by installing the Microsoft.EntityFrameworkCore.Proxies package and enabling it with a call to UseLazyLoadingProxies. For example:
In you startup.cs class modify the dbcontext as below
services.AddDbContext<BloggingContext>(
b => b.UseLazyLoadingProxies()
.UseSqlServer(myConnectionString));
Please refer the following link to understand how lazy loading works
https://learn.microsoft.com/en-us/ef/core/querying/related-data

Can I use an Interface as a property with Entity Framework?

I have the following class which is a model for a database table:
public class User : IUser
{
internal int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public ITest TestData { get; set; }
}
When I run Update-Database command, it throws an error:
The property User.TestData is of an interface type (ITest). If it is a navigation property manually configure the relationship for this property by casting it to a mapped entity type
How and where can I manually configure the relationship for this property if I do not want the actual property to be a class?
EF does not support interfaces, but you can deal with it this way. Take a look on this solution How to use interface properties with CodeFirst

Using enum as FK on EF 6

I'd like to use an enum as Foreign Key in a Code-First app. Since enums are stored as int, I thought I could use the attribute [ForeignKey] on the enum property, but it throws this exception:
The types of all properties in the Dependent Role of a referential constraint
must be the same as the corresponding property types in the Principal Role
Here is an example of what I am trying to do:
public enum UserType
{
Administrator = 1,
Member = 2
}
public class User
{
public int UserId { get; set; }
public string Login { get; set; }
[ForeignKey("TypeDetails")]
public UserType Type { get; set;}
public virtual MasterType TypeDetails { get; set; }
}
public class MasterType
{
public int MasterTypeId { get; set; }
public string Description { get; set; }
...
}
Is it possible to do this or something similar through fluent api or migrations?
Thanks
Here's one I made earlier: https://www.nuget.org/packages/ef-enum-to-lookup
It's a nuget package that provides a method you can call in your Seed (initializer and/or migrations) which will automatically build lookup tables and add FKs where the enum is used. Usage info.
Enjoy :-) And let me know if it works for you (or anyone else for that matter!)

Multiple inheritance with Entity Framework TPC

I tried to map some classes using Entity Framework in TPC style and got the following error:
Error: The type 'A' cannot be mapped as defined because it maps
inherited properties from types that use entity splitting or another
form of inheritance. Either choose a different inheritance mapping
strategy so as to not map inherited properties, or change all types in
the hierarchy to map inherited properties and to not use splitting.
This error occurs when I use the following classes:
public abstract class BaseEntityTest
public abstract class BaseEntityTest2 : BaseEntityTest
public abstract class BaseEntityTest3 : BaseEntityTest2
public class A: BaseEntityTest3 // this class is the only one with a table in the db
In the OnModelCreating method I added the following code to get the TPC mapping
modelBuilder.Entity<A>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("A");
});
When I exclude BaseEntityTest2 from the structure (so that A inherits only from BaseEntityTest instead of BaseEntityTest2) the error goes away. Does that mean that it is not possible to create this mapping or do I just miss something?
EDIT:
Properties of classes:
public abstract class BaseEntityTest
{
[Key]
public Guid Id { get; set; }
public String Info { get; set; }
[Required]
public DateTime CreationDate { get; set; }
[Required]
public String CreationUser { get; set; }
[Required]
public DateTime ModificationDate { get; set; }
[Required]
public String ModificationUser { get; set; }
[ConcurrencyCheck]
[Required]
public int LockVersion { get; internal set; }
}
public abstract class BaseEntityTest2 : BaseEntityTest
{
[Required]
public string Name { get; set; }
public string Description { get; set; }
}
public abstract class BaseEntityTest3: BaseEntityTest2
{
[Required]
public DateTime FromDate { get; set; }
public DateTime ThruDate { get; set; }
}
public class A: BaseEntityTest3{
public String Test { get; set; }
}
The error occurs for EF 4.3.1 and earlier versions, but not for EF 4.4 and EF 5.0. (EF 4.4 is actually EF 5.0, but with .NET 4.0 as target platform.)
BUT: The error occurs only if you are using your abstract classes as entities in your model, that means
you either have DbSets for them in your context class, like
public DbSet<BaseEntityTestX> BaseEntityTestXs { get; set; }
or you have some Fluent mapping for BaseEntityTestX, some modelBuilder.Entity<BaseEntityTestX>()... stuff
or you are using one of the BaseEntityTestX as a navigation property in another (concrete) entity type
Do you need any of this?
Having a DbSet<BaseEntityTestX> in your context would only make sense if you really want to query for one of the abstract entities, like:
List<BaseEntityTest> list = context.BaseEntityTests
.Where(b => b.Info == "abc").ToList();
The result is of course a list of concrete entities that inherit from BaseEntityTest, but it can be a mix of different types, like some As and some Bs. Do you need such queries? Or do you only want to query for some of the concrete objects:
List<A> list = context.As
.Where(b => b.Info == "abc").ToList();
In the latter case you don't need a DbSet for the abstract base classes and you don't need any inheritance mapping. You can just remove the DbSet<BaseEntityTestX> from your context class and remove the TPC mapping and your error will go away.
The last point - having a navigation property to one of the abstract entities in another entity - doesn't make sense with TPC mapping. It is just not mappable to a relational database because with TPC mapping there is no table for the abstract entity, hence there is no target the foreign key relationship could refer to from the table of the concrete class that has the navigation property.
The error will also disappear if you extend your TPC mapping to the base classes:
modelBuilder.Entity<BaseEntityTestX>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("BaseEntityTestX");
});
But it will create tables for those abstract entities that don't seem to make sense to me.
in EF6.0 its happed when
EntityTypeConfiguration'<'YourBaseClass'>'
did not detailed ALL your derived class with
this.Map<DerivedClass1>(m =>
{
m.MapInheritedProperties();
m.ToTable("..");
});
if just one dervied class in the assembley not configured like so
you get this exception

Auto eager load navigation property in the DbContext

Is there a way to tamper with the DbContext in order to auto eager load a specific Navigation property when the entity is requested in a query? (no lazy loading).
Entity Framework 5
Example:
var supremeEmployee = context.Employees.FirstOrDefault(x => x.EmployeeId == 42);
and the returned model would come back pre-populated with the "Department" navigation property.
Depends on what your model looks like. If you're using interfaces or inheritance you could add a function to your DbContext class with a generic constraint on that type that always includes the navigation property.
In my experience though you're usually better off not doing that, performance wise. I prefer to load into anonymous types just the fields i need in the moment.
In the most basic way you could do this:
public class Department
{
public int Id { get; set; }
}
public class Employee
{
public int Id { get; set; }
public Department Department { get; set; }
}
public class MyContext : DbContext
{
protected DbSet<Employee> Employees { get; set; }
public IQueryable<Employee> LoadEmployees()
{
return Employees.Include(p => p.Department);
}
}