MVC 5 Scaffolding with inheritance uses the wrong entity set - asp.net-mvc

With MVC 5 and EF 6.1 I am using a simple inheritance hierarchy, where class Student inherits from class Person. For both classes I have an entity set (DbSet property) in my database context:
public class DatabaseContext : DbContext
{
public DbSet<Person> Persons { get; set; }
public DbSet<Student> Students { get; set; }
}
Now when I ask the scaffolder to generate a controller for Student, the subclass, it uses the Persons entity set, leading to statements such as
Student student = db.Persons.Find(id);
where the compiler obviously complains that it cannot just convert any Person to a Student.
Is there a way to make sure that the scaffolder uses the correct entity set (Students in this case)?
Note that removing the Persons entity set is not a good solution, because there are other controllers that need that.

Use find and replace to change all occurrences in the Controller class of the parent DBSet to the child DBSet eg change Persons to Students.
As you probably know (as I think you raised it) Microsoft have confirmed this is a known bug http://connect.microsoft.com/VisualStudio/feedbackdetail/view/945937/mvc-5-scaffolding-with-inheritance-uses-the-wrong-entity-set but they won't be fixing it.

Instead of inheritance why not use a relationship making personID the Foreign key ? That why you can db.students.find(personID)
And
db.person.find(personID)
To find all details ?
Extra code but I can't think of another way

You can use the command OfType<>, as shown:
Student student = db.Persons.OfType<Student>().SingleOrDefault(s => s.id == id);
This command works with inheritance. In this case, when Student inherits from Person.

Related

Polymorphic Expand Breeze Navigation Properties

I have something like this:
public class Person {
string Name;
}
public class Customer : Person {
List<Order> orders;
}
public class MyReference {
Person aPerson;
}
public class Me {
MyReference myRef;
}
Now in my Metamodel I have specified a baseType for Customer. And I think my metamodel is right. The only problem is, that when I want to execute a query like the following:
breeze.EntityQuery.from('Me').expand('myRef, myRef.aPerson, myRef.aPerson.orders')
I get an error, that "orders" is not allowed on the EntityType "Person". Of course as it's the base-class. I would like it to be polymorphic and if the Person is really of Type "Customer" it should expand orders and if not, well then it can be empty or not defined or not even existent on the object.
Is this somehow possible? Would I need some kind of "toType" to cast inside the Query?
The base class, Person, does not have an Orders property. Therefore, .NET (EF) on the server won't let you ask for Person.Orders. That's not how polymorphism works in EF and there isn't anything Breeze can do to change that.
You'll need a different approach I'm afraid.
FWIW, that isn't how polymorphism works in Breeze either.

Entity Framework Code First : One-To-One association using Annotations

I am having .NET MVC 5 and Identity...
I am trying to get a one to one relationship for my Member class to my MemberInfo class..
So, My classes looks something like this:
IdentityUser is in the Microsoft.AspNet.Identity.EntityFramework namespace with string Id as its ID.
public class GRNUser : IdentityUser {
....
....
}
public class MemberUser : GRNUser {
public virtual Member MemberInfo {get; set; }
}
public class Member {
public int ID {get; set; }
public string MemberUserID {get; set; }
public virtual MemberUser MemberUser { get; set; }
}
In my Context, I have this
modelBuilder.Entity<Member>().HasRequired(m => m.MemberUser)
.WithOptional(u => u.MemberInfo);
So, the MemberUser and Member should be able to navigate to and from each other using the MemberUser's ID property and Member's MemberUserID property.
However, when my Database is created, it has an additional column "MemberUser_Id" instead of using my MemberUserID that I specified. How do I make it use "MemberUserID" that I specified?
I've tried using a few combination so of the ForiegnKey Data Annotation, but keeps on getting this error:
Member_MemberUser_Source: : Multiplicity is not valid in Role 'Member_MemberUser_Source' in relationship 'Member_MemberUser'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.
I don't know whether i understood you right or not, but i'l do my best to help.
(I'l assume that you work with code first migration)
If you want to make a one-to-one relation, why not try to make a standalone entity for your info which will have a foreign key for the user entity and that foreign key will be annotated as the primary key of the entity?
Another way is why just not add whatever attributes you like to the Application User entity and work with it?
In any case i might have misunderstood your purpose, so please feel free to explain further since your post is a bit confusing.

Fluent Nhibernate HasMany to One Table from Several Tables

I have an entity/class/table which is referenced from several other entities, and I use Fluent NHibernate to handle the ORM for me. In a few instances, it's a simple reference where I can store the foreign key ID as a column and handle the reference in that simple way, but in a few other instances I need to reference a list of these items, and it needs done for at least three classes I can think of. You can assume this setup will be copied to handle the other classes' relationships.
Here's how the common entity looks (the one that is owned by several other entities in HasManys):
public class Student {
public virtual int Id {get; set;}
public virtual string Name {get; set;}
}
And, here's what the ShopCourse entity looks like:
public class ShopCourse {
public virtual int Id {get; set;}
public virtual int Name {get; set;}
public virtual IList<Student> Students {get; set;}
}
Imagine that a couple other classes I have, such as specific courses, can "own" several students. In order to maintain that relationship I must create a table in my database that tracks the foreign keys between the two (for each entity that references Student) - no entity needed for this intermediate table, and Fluent won't need to think of it unless I hand it the string name of the table itself:
Table: ShopCourseStudents
int - ShopCourseId
int - StudentId
Lastly, here are my mappings. You can assume that the entities themselves map out fine - things such as the naming scheme for the Id are resolved and working correctly. The issue lies when I attempt to initialize any entity that has a HasMany of Student:
//Inside a FluentlyConfigure().Mappings(m => m.AutoMappings.Add() call:
.Override<ShopCourse>(map => {
map.HasMany(x => x.Students)
.Table("ShopCourseStudents")
.KeyColumns.Add("ShopCourseId")
.KeyColumns.Add("StudentId")
.Cascade.All();
})
The issue is that when I attempt to load a list of ShopCourses I get the Fluent error:
Foreign key (ABC123AF9:Student [ShopCourseId, StudentId]) must have
same number of columns as the referenced primary key (ShopCourses
[Id])
I do not override Fluent's mapping of Student as it's straightforward. For the purpose of this example, Student doesn't need to know which ShopCourses it belongs to, or any of the other courses that may own that particular Student record.
This seems like I'm doing something basic, wrong - what is it, exactly? Much obliged in advance!
So, the issue was with the custom code that I re-use with my projects, apparently the piece written to handle the ManyToMany convention is mostly broken. What I was looking for here was a ManyToMany relationship, not HasMany. The issue I had was that my code was forcing a reference on the child object (in this example, Student) to the parent, which I do not need and only complicates things. Removing that, and my ManyToMany then works:
.Override<ShopCourse>(map => {
map.HasManyToMany(x => x.Students)
.Table("ShopCourseStudents")
.ParentKeyColumn("ShopCourseId")
.ChildKeyColumn("StudentId")
.Cascade.All()

single entity for different tables

I have same type of tables
ProductCodeTable, CountrycodeTable etc
All have key, value as their fields
When I use entity frame work,
Can I have a single entity for all these tables such that I can formulate different queries to get data from different tables?
You can create a base class for all of them and create sub class for each entity
public abstract class LookUpEntity
{
[Key]
public int Key { get; set; }
[Required]
public string Value { get; set; }
}
[Table("ProductCodeTable")]
public class ProductCode : LookUpEntity
{
}
This way you can model the relationships also and later if you wanted to add specific properties to those look up entities with out affecting other entities.
You can create a view with a Union of all tables like this:
create view AllKeyTables as
SELECT 'Product' as table, Productkey as Key, nameProduct as name
FROM ProductCodeTable
UNION
SELECT 'Country' as table, CountryISO as key, CountryName as name
FROM CountrycodeTable
UNION
...
Then update EF model and check 'table' and 'key' fields as Entity Primary Key.
Next question you will do is: 'How can I make a relation between this Entity and existing Entities?' The answer is 'you can't because EF is not able to join Entities between other fields than primary key'. Then, before implement this solution, be sure that this is you are looking for.
EF supports this only if you model it as inheritance (#Eranga showed it in code-first approach). You will have single base entity and derived entity for each table so you will not avoid having different type for each table. Otherwise the answer is no.
Inheritance will put additional requirements on data in your tables. For example Ids will have to be unique among all tables. So if ProductTableCode will have record with Id 1, CountryCodeTable (and any other code table) mustn't have record with Id 1.
Also inheritance in EF can produce nasty and very poorly performing queries.

Automapper -- mapping many-to-many lookups from Entity Framework to viewmodel

I believe this is an AutoMapper basics question:
I have an single "article" Entity Framework entity that I am mapping to a viewmodel to pass to a view for edits. This works fine:
Mapper.CreateMap<Article, ArticleAdmin>();
var articleData = Mapper.Map<Article, ArticleAdmin>(articleEntity);
Now, my EF model includes many-to-many relation to a Topics table via a TopicArticles lookup table, and I want to manage associations when I'm editting the article data.
So I add this to my viewmodel:
public ICollection<TopicArticle> TopicArticles { get; set; }
I believe this is correct specification to mirror the entity type -- my EF model has the TopicArticles association member as an EntityCollection.
and I add a second viewmodel class to populate the list:
public class TopicArticle
{
public int ArticleId { get; set; }
public int TopicId { get; set; }
public bool IsPrimaryTopic { get; set; }
}
When I run the mapping, I get "Missing type map configuration or unsupported mapping." Which is understandable as I've not told Automapper about my TopicArticle viewmodel class.
So:
QUESTION:
How do I change my mapping to account for this extra layer?
(I don't really understand the Automapper syntax for how this should be mapped.)
Also: have I missed anything else?
NOTE / UPDATE:
There were some errors in my posted code, any "publication" that appeared was incorrect, and should have been "article" -- that was because I'm simplifying the situration a bit: articles actually inhereit from publications, but I did not want that complexity in this Question.
OK, this really is basic. My problem was not getting to the actual Automapper documentation. Googling "automapper documentation" gets this link as the top response:
http://automapper.codeplex.com/documentation
which is a useless TOC.
The real documentation is accessed from the home page.
The answer to my question is simple:
First, I change the name of my second viewmodel class for clarity:
public class TopicArticleAdmin
Then back in my action, I add one more mapping line:
Mapper.CreateMap<Publication, ArticleAdmin>();
Mapper.CreateMap<TopicPublication, TopicPublicationAdmin>();
var articles = Mapper.Map<IEnumerable<Publication>, IEnumerable<ArticleAdmin>>(
articleEntities
);

Resources