mapping columns of table to model in entity framework - asp.net-mvc

Im new to entity framework. I was trying to map 2 columns of my table(tblEnrollment) to a model(Enrollment). Before that i had changed the name of StudentIdcolumn in tblStudent in the model Student.
EntityTypeConfiguration<Student> studentEntityConfig = modelBuilder.Entity<Student>();
studentEntityConfig.ToTable("tblStudent");
studentEntityConfig.Property(p => p.StuID).HasColumnName("StudentID");
studentEntityConfig.HasKey<int>(s => s.StuID);
EntityTypeConfiguration<Enrollment> enrollmentEntityConfig = modelBuilder.Entity<Enrollment>();
enrollmentEntityConfig.Map(map =>
{
map.Properties(m => new
{
m.EnrollmentId,
m.Grade
});
});
enrollmentEntityConfig.ToTable("tblEnrollment");
Now when I'm trying to call a method to GetAllStudents from db I get the error
"The property 'Grade' on type 'Enrollment' cannot be mapped because it has been explicitly excluded from the model".
However the props Grade and enrollment have no relation to that method. They are not even in the tblStudent.

Related

ASP.Net identity, Users in role are always empty

I have implemented ASP.Net identity with some custom properties following this article -
http://typecastexception.com/post/2014/06/22/ASPNET-Identity-20-Customizing-Users-and-Roles.aspx
Everything works well, except. I want to get users under specific role (e.g. Get me all the users under Admin role).
I tried following ways to retrieve the users -
var userRole = _roleManager.Roles.SingleOrDefault(m => m.Name == role.Name);
var usersInRole = _userManager.Users.Where(m => m.Roles.Any(r => r.RoleId == userRole.Id));
var usersInRole2 = _userService.GetUsers().Where(u => u.Roles.Any(r => r.RoleId == userRole.Id));
Where _roleManager is of type ApplicationRoleManager : RoleManager<ApplicationRole>. _userManageris of type ApplicationUserManager : UserManager<ApplicationUser, string>.
I am unable to get Roles under user in _userManager and _userService
PS : _userService is service that extends IRepository which queries DbSet<ApplicationUser>.
I can see Roles being properly mapped in table ApplicationUserRoles and I get expected result when I do _userManager.IsInRole(user.Id, "Admin");.
What could've gone wrong with this?
Rahul.
If you are using Entity Framework, it sounds like you are being caught out by lazy loading (since the roles are being added to the database but not when requested from a queryable).
Try something like the following:
_userManager.Users.Include(x => x.Roles).Where(m => m.Roles.Any(r => r.RoleId == userRole.Id));
I figured out where the issue was -
Initially the table ApplicationUserRoles had only primary key definitions, not the foreign key mapping (many to many mapping)..
I added this in OnModelCreating
modelBuilder.Entity<ApplicationUserRole>().HasKey((ApplicationUserRole r) => new { UserId = r.UserId, RoleId = r.RoleId });
//added these definitions
modelBuilder.Entity<ApplicationUser>().HasMany(p => p.Roles).WithRequired().HasForeignKey(p => p.UserId);
modelBuilder.Entity<ApplicationRole>().HasMany(p => p.Users).WithRequired().HasForeignKey(p => p.RoleId);
This completed the relationship and now I can see the Users under Roles and vice versa.
This resulted issue while updating the database, however I just had to do some changes in migration -
The object 'PK_Dbo.ApplicationUserRole' is dependent on column
'UserId'. ALTER TABLE DROP COLUMN UserId failed because one or more
objects access this column.
All I did is, I went to the migration file and moved these lines above DropColumn
DropIndex("dbo.ApplicationUserRole", new[] { "ApplicationUser_Id" });
DropIndex("dbo.ApplicationUserRole", new[] { "ApplicationRole_Id" });
DropPrimaryKey("dbo.ApplicationUserRole");
This solved the update-database exceptions as well.
Rahul

Does model_name.new() in ActiveRecord create only new records or update existing as well

I have a model that I use with active record in a ruby script below. Things like level_type, name, parent.id, and pipcode get assigned to the attributes of the model for entry into the levels table. My question is, does this only work for new records? you see, the name, parent.id, and pipcode get changed often. I dont want it to create a new record everytime these values change. I would like it to update existing records with the new values coming in from pipcode, parent.id etc..
My record creation code:
new_region = Level.new(
:level => level_type,
:name => name,
:parent_id => parent.id,
:make_code => pipcode
)
Level.new(...) is usually used to create a new row when you call new_region.save()
If you want to update, first you need to find the row you want to update by calling something like:
# if patient_id is the primary key
existing_region = Level.find(patient_id)
At this point, you can update the existing_region's parameters and call .save() to update the database.
existing_region.level = level_type
existing_region.name = name
...
existing_region.save()

How to Seed value to aspnet_UsersInRoles in EntityFramework

I'm currently creating an application with EntityFramework and aspnet membership tables combined.
To create the aspnet membership tables dynamically, I followed this tutorial: http://imar.spaanjaars.com/563/using-entity-framework-code-first-and-aspnet-membership-together
My problem is the aspnet_UsersInRoles table. To map the table I modified OnModelCreating and add the ff code:
modelBuilder.Entity<AspnetUser>()
.HasMany(u => u.AspnetRoles)
.WithMany(r => r.AspnetUsers)
.Map(m =>
{
m.ToTable("aspnet_UsersInRoles");
m.MapLeftKey("UserId");
m.MapRightKey("RoleId");
});
It created successfully the aspnet_UsersInRoles table, but my problem is that I don't have a class/entity for this and I'm unable to initialize value when I override the Seed method.
Creating an entity aspnet_UsersInRoles also doesn't work because the many-to-many relationship between aspnet_Users and aspnet_Roles create a new table.
Any idea on how to do this? Having many to many relationship between aspnet_Users and aspnet_Roles using the table aspnet_UsersInRoles and initializing values in it.
You need to add the Roles to AspnetRoles collection property of the AspnetUser class.
var role = new AspnetRole { Name = "Foo" };
var user = new AspnetUser { Name = "Bar", /*other props*/ };
user.AspnetRoles = new List { role };
context.Users.Add(user);
This will add "Foo" role to the "Bar" user.

FLuent nHibernate Linq Query

I m facing issue to access the bridge table to get the values using nHibernate and LINQ.
I have 4 table, ROLES , MODULES , PERMISSIONS and the RoleModulePermission(bridge).
Roles contains ROLEID(pk) , ROLENAME
Modules contains MODULEID(pk) , MODULENAME
Permission contains PERMISSIONID , PERMISSIONTYPE
RoleModulePermission contains ROLEID , MODULEID and PERMISSIONID
I want to get the Modules n Permission applied to the ROLES on the basis of ROLEID.
Role Mapping
Table("tblRoles");
Id(role => role.RoleID).GeneratedBy.Identity();
Map(role => role.RoleName).Not.Nullable();
Map(role => role.IsActive).Not.Nullable();
Map(role => role.Description).Not.Nullable();
HasManyToMany(x => x.Users)
.Table("tblUserInRoles")
.ParentKeyColumn("RoleID")
.ChildKeyColumn("UserID")
.Not.LazyLoad();
HasManyToMany(x => x.Modules)
.Table("tblRolesPermission")
.ParentKeyColumn("RoleID")
.ChildKeyColumn("ModuleID")
.Not.LazyLoad();
HasManyToMany(x => x.Permissions)
.Table("tblRolesPermission")
.ParentKeyColumn("RoleID")
.ChildKeyColumn("PermissionID")
.Not.LazyLoad();
Module Mapping
Table("tblAppModules");
Id(mod => mod.ModuleID).GeneratedBy.Identity();
Map(mod => mod.ModuleName).Nullable();
Map(mod => mod.CreationDate).Nullable();
HasManyToMany(x => x.Roles)
.Table("tblRolesPermission")
.ParentKeyColumn("ModuleID")
.ChildKeyColumn("RoleID")
.Not.LazyLoad();
Permission Mapping
Table("tblPermission");
Id(p => p.PermissionID).GeneratedBy.Identity();
Map(p => p.PermissionType).Not.Nullable();
HasManyToMany(p => p.PermitRole)
.Table("tblRolesPermission")
.ParentKeyColumn("PermissionID")
.ChildKeyColumn("RoleID")
.Not.LazyLoad();
It seems that i did wrong in mapping ?
please do not assume 'AllowAccess' in tblRolesPermission
How to achieve this ?
Thanks
Mapping for ternary associations in FluentNHibernate depends from specifics of your scenario and domain model.
Basically, if you are going to have the many-to-many relations everywhere (i.e. your Module can have multiple Permissions, Role can have multiple Permissions and Role can have multiple Modules), you'll need to have a separate entity for the relation, called i.e. RoleModulePermission. It will change your graph from triangle-like (3 classes) into a star-like (4 classes with common "root"). The new entity will have three many-to-one relations and Role, Module and Permission will have one-to-many relation to RoleModulePermission. Set up the cascades and you can try querying this model like any other:
session.Query<Permission>()
.Where(x => x.RoleModules.Any(rm => rm.Module == module));
If your model is more restricted, i.e. you have some constraints, you can try to map it simpler using AsTernaryAssociation or AsEntityMap, which is pretty much the same. Then in your Role, Module and Permission classes you should have relation of type IDictionary<TFrom, To>. This can mean i.e. that Permission X maps Role Y to Module Z, but it means that within Permission X Role Y have no other Modules. Something like this in POCO class:
public virtual IDictionary<Role, Module> RoleModules { get; set; }
and like this in mapping:
HasManyToMany(x => x.RoleModules).Table("tblRolesPermissions").AsEntityMap();
does support it, but. You have to specify one-to-many or many-to-many relations at each side of the relation (in POCO's for Roles, Modules and Permission) and map each relation like that:
m.HasMany(x => x.RolesPermissionsModules).AsTernaryAssociation()
Querying using LINQ should then look somehow like this:
session.Query<Permission>()
.Where(x => x.RoleModules[role] == module);

Fluent NHibernate - Mapping a property to a column on a joined table

I've got a couple tables, for example:
Product {Id, Name, ManufacturerId, ...}
Manufacturer {Id, Name, ...}
I'd like to be able to include ManufacturerName on my Product object (instead of having to load the whole Manufacturer row when I only need the name). My ProductMap looks like...
Table("Product");
Id(x => x.Id, "Id");
Map(x => x.ProductName, "ProductName");
Map(x => x.ManufacturerId, "ManufacturerId");
References(x => x.Manufacturer, "ManufacturerId");
What do I need to add to populate the ManufacturerName property on my Product object? I believe I need to make some sort of Join() call, but I'm having trouble figuring out how to write it with all the relevant parameters. It needs to join the current table (Product) to the Manufacturer table, on Product.ManufacturerId = Manufacturer.Id, and grab the Manufacturer.Name column, populating the ManufacturerName property on the object.
I think you could use a formula to dynamically retrieve a manufacturer name. This is not an elegant solution and personally I would prefer using a separate sql view mapped to a new entity (e.g. ProductExtra, etc.) where it would query just necessary columns but anyways. Here we go:
Add the ManufacturerName property to the Product class
Add a mapping line for that new property to your ProductMap:
Table("Product");
Id(x => x.Id, "Id");
Map(x => x.ProductName, "ProductName");
Map(x => x.ManufacturerId, "ManufacturerId");
Map(x => x.ManufacturerName).Formula("(select m.ManufacturerName from Manufacturer m where m.Id = ManufacturerId)");
References(x => x.Manufacturer, "ManufacturerId");
Hope this helps.
NH Joins are tricky, and require things that your schema may not support. For instance, the joined table's primary key is matched to your current table's primary key. It works a lot like a OneToOne mapping, except NH won't create an explicit constraint to that effect. Since this isn't the case in your mapping (looks like a many-to-one reference), I doubt you could make an explicit join work.
Try mapping a "pass-through" property:
public class Product
{
...
public string ManufacturerName
{
get{return NHibernateUtil.IsInitialized(Manufacturer)
? Manufacturer.Name : manufacturerName;}
set{if(NHibernateUtil.IsInitialized(Manufacturer))
Manufacturer.Name = value
else
manufacturerName = value;}
}
}
...
//In your mapping:
Map(x => x.ManufacturerName, "ManufacturerName");
This will persist a normalized Manufacturer's name onto the Product table as a denormalized field. The field will also exist in the Manufacturer table. When you retrieve JUST the Product, you get the name from the Product table. After the Manufacturer is lazy-initialized for some other reason (or eager-loaded), you get the name from the Manufacturer table, which then means you can persist the Manufacturer record's name to the Product.

Resources