Code First Entity / MVC4 - why aren't my models hydrated? - asp.net-mvc

I can not figure out what I'm doing wrong here. New to MVC and new to Entity, so I know that's holding me back. Any time I call up AuthUser, AuthRole is always nothing, so I end up doing something like:
authuser.AuthRole = db.AuthRoleSet.Find(2) 'AuthRoleID of 2 = User
This just feels clunky to me. How do I get my property to actually get the role with the user?
Here's my class structure:
Public Class AuthUser
'Class Globals
Dim db As New AuthUserContext
'Properties
Public Property AuthUserID() As Integer
<Required()> _
<Display(Name:="User Name")> _
<DomainUserValidation()> _
Public Property UserName() As String
<Display(Name:="Current Role")> _
Public Property AuthRole As AuthRole
End Class
Public Class AuthRole
Public Property AuthRoleID() As Integer
<Required()> _
<Display(Name:="Role Name")> _
Public Property RoleName() As String
<Required()> _
<Display(Name:="Is Administrator")> _
Public Property isAdministrator() As Boolean
<Required()> _
<Display(Name:="Is Active")> _
Public Property isActive() As Boolean
<Required()> _
Public Property AuthUser As ICollection(Of AuthUser)
End Class
Public Class AuthUserContext
Inherits DbContext
Public Property AuthUserSet() As DbSet(Of AuthUser)
Public Property AuthRoleSet() As DbSet(Of AuthRole)
End Class

You have 2 options (sorry c# syntax):
1 - Lazy load AuthRole when you need it - for this, your AuthRole property needs to be declared as virtual
public virtual AuthRole {get;set;}
Now, when/if you try to access AuthRole, EF will get it from database.
For this to work you need to have DbContext.Configuration.LazyLoadEnabled = true
Another alternative is to eager load it by using a query like this:
var myUserWithRole = myContext.AuthUsers.Include("AuthRole").FirstOrDefault(x=>x.Id == userId);
This will get the user and the role from the database.

Related

OData v4 $orderby on a child derived property

I have the following scenario:
public class Stay
{
[Contained]
public Guest PrimaryGuest {get;set;}
}
public abstract class Guest
{
public int ID {get; set;}
}
public class EntityGuest : Guest
{
public string EntityName {get;set;}
}
public class PersonGuest : Guest
{
public string SurName {get;set;}
public string GivenName {get;set;}
}
When querying for the stays, I wish to order by a PersonGuest/SurName.
I know how to order by a child property: [URL]/Stays?$expand=PrimaryGuest&$orderby=PrimaryGuest/ID - but how would I order by on a child property that is derived? Is it even possible? I could not determine it by the OData documentation - it wasn't at least called out for contained entities.
This answer helped me a lot in a similar scenario: oData $expand on Derived Types
Basically you can 'Cast' any complex or entity typed property in your query by adding a forward slash and the qualified name of the model type, using the namespace you have defined for your model, not the .Net full type name.
[URL]/Stays?$expand=PrimaryGuest&$orderby=PrimaryGuest/ModelNamespace.PersonGuest/Surname
If you are unsure of the model namespace, look at the model builder code, or use something similar to this:
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.Namespace = "MyAppModel";
Then your URL should look like this:
[URL]/Stays?$expand=PrimaryGuest&$orderby=PrimaryGuest/MyAppModel.PersonGuest/Surname

how to manually insert primary key while inserting a row - EF

I am using MVC 4 with Visual studio 2012. I want to insert primary key while creating row. My tables as as :
<Table("StudentRec")> _
Public Class StudentRec
<Key()> _
Public Property ErNo as Integer
Public Property Name as String
Public Property Branch as String
Public Property Course as String
End Class
<Table("Attendance")> _
Public Class Attendance
<Key()> _
Public Property ErNo as Integer
Public Property Present as Integer
Public Property Leaves as Integer
End Class
My Action Controller is :
<HttpPost()> _
<AllowAnonymous()> _
<ValidateAntiForgeryToken()> _
Function CreateUser(ByVal Modl As StudentRec) As ActionResult
Try
Using dbb As New UsersContext
Dim Erno As Integer = dbb.StudentRec_.Add(Modl).ErNo
dbb.SaveChanges()
Dim Attnd As New Attendance
Attnd.ErNo = Erno ' Not Working, Erno is automatically Set '
Attnd.Leaves = 0
Attnd.Present = 0
dbb.Attendance_.Add(Attnd)
dbb.SaveChanges()
End Using
RedirectToAction("Index", "Home")
Catch ex As Exception
TempData("Errs") = ex.Message
Return View(Modl)
End Try
Return View(Modl)
End Function
How to Manually Set Primary key to table Attendance, with respect to Primary Key of table StudentRec ?

Select Specific Fields With Condition And Convert to List in Entity Framework

This is my table structure:
Partial Public Class KeyTable
Public Property KeyID As Long
Public Property ServiceName As String
Public Property Pricing As Nullable(Of Integer)
Public Property Active As Nullable(Of Boolean)
Public Property Description As String
Public Property Created As Nullable(Of Date)
End Class
This is a class I have
Public Class Service
Public KeyID As Double
Public ServiceName As String
End Class
I want to select the following fields
Select KeyID, ServiceName from KeyTable where Created= GivenDate
And convert the results to List (Of Service)
Here's what I tried so far:
Using db As New ServicesEntities()
Dim x = (From e1 In db.KeyTables Where e1.Created = sc Select e1.KeyID,e1.ServiceName).ToList()
End Using
You can try the following:
Using _DB As New ServicesEntities()
Dim _Services As List(Of Service) = (From e1 In _DB.KeyTables Where e1.Created = sc).ToList().ConvertAll(Function(Record) New Service With{.KeyID = Record.KeyId, ServiceName = Record.ServiceName }).ToList()
End Using

The ForeignKeyAttribute on property is not valid

I've read How Should I Declare Foreign Key Relationships Using Code First Entity Framework (4.1) in MVC3? but I can't get my call to yield any results. It has the following error:
The ForeignKeyAttribute on property 'Footer_Item_Header_ID' on type
'MyBlog.Tbl_Footer_Item' is not valid. The navigation property
'Tbl_Footer_Header' was not found on the dependent type
'MyBlog.Tbl_Footer_Item'. The Name value should be a valid navigation
property name.
On this line:
Dim footerNavElements = db.Tbl_Footer_Headers.Where(Function(i) i.Footer_Header_Order = 1).Single.Items
Here is my parent model:
Imports System.Data.Entity
Imports System.ComponentModel.DataAnnotations
Public Class Tbl_Footer_Header
<Key()> Public Property Footer_Header_ID() As Integer
Public Property Footer_Header_Content() As String
Public Property Footer_Header_Order() As Integer
Public Overridable Property Items As ICollection(Of Tbl_Footer_Item)
End Class
Public Class FooterHeaderDbContext
Inherits DbContext
Public Property Tbl_Footer_Headers As DbSet(Of Tbl_Footer_Header)
End Class
Here is my child model:
Imports System.Data.Entity
Imports System.ComponentModel.DataAnnotations
Public Class Tbl_Footer_Item
<Key()> Public Property Footer_Item_ID() As Integer
<ForeignKey("Tbl_Footer_Header")>
Public Property Footer_Item_Header_ID() As Integer
Public Property Footer_Item_Content() As String
Public Property Footer_Item_Link() As String
Public Property Footer_Header_Order() As Integer
Public Overridable Property Header As Tbl_Footer_Header
End Class
Public Class FooterItemDbContext
Inherits DbContext
Public Property Tbl_Footer_Items As DbSet(Of Tbl_Footer_Item)
Public Property Tbl_Footer_Headers As DbSet(Of Tbl_Footer_Header)
End Class
What can I do to make the action yield a result without error? Thanks.
Your foreign key is annotation should be for the name of the property, not the type.
Your navigation property is Header:
Public Overridable Property Header As Tbl_Footer_Header
So your annotation, should reference the property. Change it to:
<ForeignKey("Header")>
Public Property Footer_Item_Header_ID() As Integer

Composing polymorphic objects in ASP.NET MVC3 project

The essence of my question is how to compose these objects (see below) in a sensible way with MVC3 and Ninject (though I am not sure DI should be playing a role in the solution). I can't disclose the real details of my project but here is an approximation which illustrates the issue/question. Answers in either VB or C# are appreciated!
I have several different products with widely varying properties yet all of them need to be represented in a catalog. Each product class has a corresponding table in my database. A catalog entry has a handful of properties specific to being a catalog entry and consequently have their own table. I have defined an interface for the catalog entries with the intent that calling the DescriptionText property will give me very different results based on the underlying concrete type.
Public Class Clothing
Property Identity as Int64
Property AvailableSizes As List(Of String)
Property AvailableColor As List(Of String)
End Class
Public Class Fasteners
Property Identity as Int64
Property AvailableSizes As List(Of String)
Property AvailableFinishes As List(Of String)
Property IsMetric As Boolean
End Class
Public Interface ICatalogEntry
Property ProductId as Int64
Property PublishedOn As DateTime
Property DescriptionText As String
End Interface
Given that the DescriptionText is a presentation layer concern I don't want to implement the ICatalogEntry interface in my product classes. Instead I want to delegate that to some kind of formatter.
Public Interface ICatalogEntryFormatter
Property DescriptionText As String
End Interface
Public Class ClothingCatalogEntryFormatter
Implements ICatalogEntryFormatter
Property DescriptionText As String
End Class
Public Class FastenerCatalogEntryFormatter
Implements ICatalogEntryFormatter
Property DescriptionText As String
End Class
In a controller somewhere there will be code like this:
Dim entries As List(Of ICatalogEntry)
= catalogService.CurrentCatalog(DateTime.Now)
In a view somewhere there will be code like this:
<ul>
#For Each entry As ICatalogEntry In Model.Catalog
#<li>#entry.DescriptionText</li>
Next
</ul>
So the question is what do the constructors look like? How to set it up so the appropriate objects are instantiated in the right places. Seems like generics or maybe DI can help with this but I seem to be having a mental block. The only idea I've come up with is to add a ProductType property to ICatalogEntry and then implement a factory like this:
Public Class CatalogEntryFactory
Public Function Create(catEntry as ICatalogEntry) As ICatalogEntry
Select Case catEntry.ProductType
Case "Clothing"
Dim clothingProduct = clothingService.Get(catEntry.ProductId)
Dim clothingEntry = New ClothingCatalogEntry(clothingProduct)
Return result
Case "Fastener"
Dim fastenerProduct = fastenerService.Get(catEntry.ProductId)
Dim fastenerEntry = New FastenerCatalogEntry(fastenerProduct)
fastenerEntry.Formatter = New FastenerCatalogEntryFormatter
Return fastenerEntry
...
End Function
End Class
Public ClothingCatalogEntry
Public Sub New (product As ClothingProduct)
Me.Formatter = New ClothingCatalogEntryFormatter(product)
End Sub
Property DescriptionText As String
Get
Return Me.Formatter.DescriptionText
End Get
End Property
End Class
...FastenerCatalogEntry is omitted but you get the idea...
Public Class CatalogService
Public Function CurrentCatalog(currentDate as DateTime)
Dim theCatalog As List(Of ICatalogEntry)
= Me.repository.GetCatalog(currentDate)
Dim theResult As New List(Of ICatalogEntry)
For Each entry As ICataLogEntry In theCatalog
theResult.Add(factory.Create(entry))
Next
Return theResult
End Function
End Class
IMHO, I am not really getting any smells off this code other than having to change the factory for every new product class that comes along. Yet, my gut says that this is the old way of doing things and nowadays DI and/or generics can do this better. Suggestions on how to handle this are much appreciated (as are suggestions on a better title...)
I like to just use the default constructor on models for the view and populate them via Automapper.
I would have a view model like this:
public interface IHasDescription
{
public string DescriptionText { get; set; }
}
public class ViewModelType : IHasDescription
{
[DisplayName("This will be rendered in the view")]
public string SomeText { get; set; }
public string DescriptionText { get; set; }
}
And I have a model from the DAL like this:
public class DALModelType
{
public string SomeText { get; set; }
}
So you have something like this in your controller:
var dalModel = someRepository.GetAll();
var viewModel = Mapper.Map<DALModelType, ViewModelType>(dalModel);
And you have the Automapper setup code in some file. This way you only have the conversion code in one place instead of in multiple methods/controllers. You have a custom resolver which uses dependency injection (instead of () => new CustomResolver()) and this will house your logic for getting the display text.
Mapper.CreateMap<IHasDescription, ViewModelType>()
.ForMember(dest => dest.DescriptionText,
opt => opt.ResolveUsing<CustomResolver>().ConstructedBy(() => new CustomResolver()));
Not sure if this works with your workflow but it should be able to get you what you want.
So making a few small changes I got this to work using the Ninject Factory extension.
Biggest change is that my entities have enough info to display either type (clothes or fasteners in my contrived example) if the item is actually clothes then the fastener specific properties will be null and vice versa.
Public Interface IDescribable
ReadOnly Property DescriptionText As String
End Interface
Public Enum ProductType
CLOTHING
FASTENER
End Enum
Public Interface ICatalogEntry
Inherits IDescribable
ReadOnly Property ProductId As Int64
ReadOnly Property PublishedOn As DateTime
ReadOnly Property ProductType As ProductType
End Interface
Public Class CatalogEntryEntity
Public Property ProductId As Long
Public Property ProductType As ProductType
Public Property PublishedOn As Date
Public Property DescriptionText As String
Public Property Color As String
Public Property Finish As String
Public Property IsMetric As Boolean
End Class
Then with this in place I can define my catalog service as follows:
Public Class CatalogService
Private ReadOnly _factory As ICatalogEntryFactory
Private ReadOnly _repository As CatalogRepository
Public Sub New(entryFactory As ICatalogEntryFactory, repository As CatalogRepository)
Me._factory = entryFactory
Me._repository = repository
End Sub
Public Function CurrentCatalog(currentDate As DateTime) As List(Of ICatalogEntry)
Dim items = Me._repository.GetCatalog()
Return (From item In items Select _factory.Create(item.ProductType.ToString(), item)).ToList()
End Function
End Class
Public Interface ICatalogEntryFactory
Function Create(bindingName As String, entity As CatalogEntryEntity) As ICatalogEntry
End Interface
Ninject will provide the factory (which is awesome!) assuming I setup the bindings like this:
theKernel.Bind(Of ICatalogEntry)().To(Of ClothingCatalogEntry)().Named("CLOTHING")
theKernel.Bind(Of ICatalogEntry)().To(Of FastenerCatalogEntry)().Named("FASTENER")
theKernel.Bind(Of ICatalogEntryFactory)().ToFactory(Function() New UseFirstParameterAsNameInstanceProvider())
I've omitted the FastenerCatalogEntry for brevity; the ClothingCatalogEntry is like this:
Public Class ClothingCatalogEntry
Public Sub New(ByVal entity As CatalogEntryEntity)
...
It was this post that helped me the most to figure this out. I used UseFirstParameterAsNameInstanceProvider exactly as shown there.

Resources