Populating a ViewModel from a database model - asp.net-mvc

I have a ViewModel that inherits a database model. I can't work out how to populate the ViewModel from the database.
"ViewModel"
Public Class CustomerView
Inherits Customer
Private lookUp As New LookUpData
ReadOnly Property OwnerList As List(Of SelectListItem)
Get
Return lookUp.OwnersList(True)
End Get
End Property
End Class
"Controller"
Function Edit(Optional Id As Integer = Nothing) As ActionResult
Dim model As New CustomerView
model = (From c In db.Customers Where c.Id = Id AndAlso c.OrganisationId = s.OrganisationId).FirstOrDefault
If model Is Nothing Then
Return RedirectToAction("List")
Else
Return View(model)
End If
End Function
I get an invalid cast exception.
Any help would be greatly appreciated.

Your Linq query is returning (I assume) as list of Customer object which you need to project into your view model object. Change your Linq by adding a select:
model = (From c In db.Customers _
Where c.Id = Id AndAlso _
c.OrganisationId = s.OrganisationId _
Select New CustomerView With { _
.CompanyName = c.CompanyName, _
.Address = c.Address, _
.City = cust.City, _
.Country = cust.Country}).FirstOrDefault
Been a while since I did VB, but that should either work or require only a tweak.

Related

Updated ComplexObject values AfterSaveEntities: missing from server to client

I am calculating some values in the AfterSaveEntities method on the server using Breeze EFContextProvider. I am doing this for several different entity types.
After I calculate the new values, I save them to the datastore (using a new datacontext as specified in other SO questions).
I also update the entities in the saveMap with these new scalar values. These values are just integer properties that make up a ComplexObject that is a property of the entity being saved.
Everything works great. I can see just before my SaveChanges API function returns to client, that the properties are my ComplexObject are all correct.
Now, for most of my entity types, when the saveResult hits the client, everything is as expected. EXCEPT...for one of my entity types.
For this problem entity, the properties of the ComplexObject are not getting updated. If I look at the client-side complexAspect.originalValues property of the ComplexObject, the originalValues are the values I'm expecting to be the actual values the object...the same values that it had just before it left the server in the SaveChanges result.
I'm wondering if the answer is with adjusting entityInfo.OriginalValuesMap in the AfterSaveEntities function. But it didn't seem to make a different. I wonder if working with Complex Objects requires a different syntax when adjusting the OriginalValuesMap.
EDIT: I discovered that this unexpected behavior happens only when I create a new EntityInfo and add it to the SaveMap Dictionary in AfterSaveEntities.
The new entities that I create via CreateEntityInfo(entity, Breeze.ContexProvider.EntityState.Unchanged) are added to the saveMap with proper Type as the key.
Ironically, these extra entities all have the properties on their complex objects show up fine on client side. But as soon as I add more entities to the saveMap is when my original entity (that is already in the saveMap) starts messing up.
I hope I made my problem clear enough.
Here's my solution for anyone else with this problem...
The problem goes back to having 2 datacontexts...I needed a 2nd one to load related entities to do calculations for business logic.
I was adding entities from my 2nd context back into the SaveMap...I fixed this by instead loading those entities from the original breeze context and saving THOSE into the SaveMap.
Protected Overrides Sub AfterSaveEntities(saveMap As Dictionary(Of Type, List(Of EntityInfo)), keyMappings As List(Of KeyMapping))
Dim context2 = New Data.Db(EntityConnection)
context2.Configuration.ProxyCreationEnabled = False
context2.Configuration.LazyLoadingEnabled = False
Dim newEntitiesMap As New Dictionary(Of Type, EntityInfo)
For Each entType In saveMap
Select Case entType.Key.Name
Case "Registration"
For Each ent In entType.Value
Dim registration = DirectCast(ent.Entity, Registration)
registration.Stats = GenerateRegistrationStats(context2, registration.Id)
Next
Case "ConferenceRoom"
For Each ent In entType.Value
Dim conferenceRoom = DirectCast(ent.Entity, ConferenceRoom)
conferenceRoom.Stats = GenerateConferenceRoomStats(context2, conferenceRoom.Id)
Next
Case "Reservation"
For Each ent In entType.Value
Dim reservation = DirectCast(ent.Entity, Reservation)
reservation.Stats = GenerateReservationStats(context2, reservation.Id)
''Update ConferenceRoom stats
Dim confRoom = Me.Context.ConferenceRooms.Find(reservation.ConferenceRoomId)
confRoom.Stats = GenerateConferenceRoomStats(context2, confRoom.Id)
AddToSaveMap(newEntitiesMap, confRoom, GetType(ConferenceRoom))
''Update Registration stats
Dim registration = Me.Context.Registrations.Find(reservation.RegistrationId)
registration.Stats = GenerateRegistrationStats(context2, registration.Id)
AddToSaveMap(newEntitiesMap, registration, GetType(Registration))
Next
Case "Registree" 'update
For Each ent In entType.Value
Dim registree = DirectCast(ent.Entity, Registree)
Dim registration = Me.Context.Registrations.Find(registree.RegistrationId)
registration.Stats = GenerateRegistrationStats(context2, registration.Id)
AddToSaveMap(newEntitiesMap, registration, GetType(Registration))
Next
End Select
Next
context2.SaveChanges()
For Each ent In newEntitiesMap
If saveMap.ContainsKey(ent.Key) Then
'add to existing list
saveMap(ent.Key).Add(ent.Value)
Else
Dim list As New List(Of EntityInfo) From {ent.Value}
saveMap.Add(ent.Key, list)
End If
Next
End Sub
Private Sub AddToSaveMap(AddToSaveMap As Dictionary(Of Type, EntityInfo), entity As Object, classType As Type)
Dim entInfo = Me.CreateEntityInfo(entity, Breeze.ContextProvider.EntityState.Unchanged)
AddToSaveMap.Add(classType, entInfo)
End Sub
Private Function GenerateConferenceRoomStats(context As Data.Db, conferenceRoomId As Integer) As ConfRoomStats
Dim confRoom = context.ConferenceRooms.Where(Function(x) x.Id = conferenceRoomId) _
.Include(Function(x) x.Reservations.Select(Function(r) r.Occupants)).FirstOrDefault
confRoom.Stats = confRoom.GenerateStats
Return confRoom.Stats
End Function
Private Function GenerateReservationStats(context As Data.Db, reservationId As Integer) As ReservationStats
Dim reservation = context.Reservations.Where(Function(x) x.Id = reservationId) _
.Include(Function(x) x.Occupants).FirstOrDefault
reservation.Stats = reservation.GenerateStats
Return reservation.Stats
End Function
Private Function GenerateRegistrationStats(context As Data.Db, registrationId As Integer) As RegStats
Dim registration = context.Registrations.Where(Function(x) x.Id = registrationId) _
.Include(Function(x) x.Registrees.Select(Function(r) r.Person)) _
.Include(Function(x) x.Estimates) _
.Include(Function(x) x.Reservations.Select(Function(r) r.ConferenceRoom)) _
.Include(Function(x) x.Reservations.Select(Function(r) r.Occupants)).FirstOrDefault
registration.Stats = registration.GenerateStats
Return registration.Stats
End Function

How to Fill Drop Down List using Model in MVC

Function GetStateName() As List(Of SelectListItem)
Dim ListRoomMaster As List(Of MiscMaster) = New List(Of MiscMaster)
Dim rm As New MiscMaster
Using conn As New SqlConnection(connectionString)
Dim sSql = "Select * From dropdown"
Dim cmd As SqlCommand = New SqlCommand(sSql, conn)
conn.Open()
Dim rst As SqlDataReader = cmd.ExecuteReader
Do While rst.Read
rm.m_ddlId = rst!id
rm.ddlValue = rst!name
ListRoomMaster.Add(rm)
Loop
End Using
Dim Listxyz = (
From p In Enumerable.Range(0, 20)
Select New SelectListItem With {.Text = p.ToString(), .Value = p.ToString()})
Return Listxyz.ToList()
End Function
This is the code for GetStateName() Which I am calling from controller Before Viewing This Displays The Drop Down List With 0 to 19 numbers I know I have Miss Something But Don't Know Where to change as most of code are for Linq
This Is Controller Code
Function Index() As ActionResult
objMisc.StateValue = objMisc.GetStateName()
'objMisc.StateValue = obj
Return View(objMisc)
End Function
What I Exactly Want Is Fetching data from DataBase using query
DataBase Have field like follow
id | Value
1 | xyz
2 | abx
3 | kvd
I want to populate drop down List As xyz,abx,kvd
And when abx is selected I want to store 2 in database
If you are working with MVC then you can also get the Data directly in the Razor View from your Model. Because you are doing a SQL Query manually which isnt the puropse of MVC.
Your should return the Model and then you can simply do this:
#Html.DropDownListFor(m => m.column, Model.dropdown)
Let's make a couple of models:
public NameCode(string name)
{
Name = name;
Code = name;
}
public NameCodeCollection(IEnumerable<NameCodeItem> list) : base(list)
{
}
In razor:
#Html.DropDownListFor(m => m.modelid, new SelectList(Model.modeltext, "Name", "Code"))
Use the namecodecollection to feed your dropdown list & read from it.

Can't get Database to update using Repository Pattern and LINQ to SQL

My project has the following setup
Controller -> Service (for validation) -> Repository (for LINQ) -> dbml -> Database
Controller
''# <AcceptVerbs(HttpVerbs.Post)> - hiding this line so that code formatting looks proper in SO.
Function Edit(ByVal user As Domain.User, ByVal id As Integer) As ActionResult
If ModelState.IsValid Then
If Not String.IsNullOrEmpty(user.UserName) AndAlso _
Not String.IsNullOrEmpty(user.WebSite) AndAlso _
Not String.IsNullOrEmpty(user.Email) AndAlso _
Not String.IsNullOrEmpty(user.About) AndAlso _
Not user.Region Is Nothing AndAlso _
Not user.BirthDate Is Nothing AndAlso _
Not user.isProfileComplete = True Then
user.isProfileComplete = True
user.Reputation = user.Reputation + 10
UserService.UpdateUser(user)
Else
UserService.UpdateUser(user)
End If
UserService.SubmitChanges()
Return RedirectToAction("Details", "Users", New With {.id = id, .slug = user.UserName})
Else
Return View(user)
End If
End Function
Service
Public Sub UpdateUser(ByVal user As User) Implements IUserService.UpdateUser
_UserRepository.UpdateUser(user)
End Sub
Public Sub SubmitChanges() Implements IUserService.SubmitChanges
_UserRepository.SubmitChanges()
End Sub
Repository
Public Sub UpdateUser(ByVal user As User) Implements IUserRepository.UpdateUser
Dim _user = (From u In dc.Users
Where u.ID = user.ID
Select u).Single
_user = user
End Sub
Public Sub SubmitChanges() Implements IUserRepository.SubmitChanges
dc.SubmitChanges()
End Sub
The problem is that it's not getting updated. I must be doing something quite stupid here. Any advice will be greatly appreciated.
Public Sub UpdateUser(ByVal user As User) Implements IUserRepository.UpdateUser
Dim _user = (From u In dc.Users
Where u.ID = user.ID
Select u).Single
_user = user
End Sub
In this method, you are getting the User from the database. That User instance is being tracked by Linq2Sql in terms of knowing if the properties have changed. So, after the linq statement _user is known by the data context and can be tracked. When you assign the user parameter to the object (_user = user), you lose the reference to the tracked object, and replace it with an untracked object. You can either individually update the _user variable that contains information from the database, or attempt to attach the user parameter to the data context and use that directly (dc.Users.Attach(user)). Attaching can be complex because if you don't have the same datacontext instance than it won't attach properly. Below is how I would do it.
Public Sub UpdateUser(ByVal user As User) Implements IUserRepository.UpdateUser
Dim _user = (From u In dc.Users
Where u.ID = user.ID
Select u).Single
With _user
.Name = user.Name
.Email = user.Email
End With
End Sub

How does Select statement works in a Dynamic Linq Query?

1) I've a Product table with 4 columns: ProductID, Name, Category, and Price. Here's the regular linq to query this table.
public ActionResult Index()
{
private ProductDataContext db = new ProductDataContext();
var products = from p in db.Products
where p.Category == "Soccer"
select new ProductInfo { Name = p.Name, Price = p.Price}
return View(products);
}
Where ProductInfo is just a class that contains 2 properties (Name and Price). The Index page Inherits ViewPage - IEnumerable - ProductInfo. Everything works fine.
2) To dynamicaly execute the above query, I do this:
Public ActionResult Index()
{
var products =
db.Products
.Where("Category = \"Soccer\"")
.Select(/* WHAT SOULD I WRITE HERE TO SELECT NAME & PRICE?*/)
return View(products);
}
I'm using both 'System.Lind.Dynamic' namespace and the DynamicLibrary.cs (downloaded from ScottGu blog).
Here are my questions:
What expression do I use to select only Name and Price?
(Most importantly) How do I retrieve the data in my view? (i.e. What type the ViewPage inherits? ProductInfo?)
===================
EDIT
When I write .Select("new(Name, Price)"), I'm able to pass an object to the ViewData's Model property. Unfortunately, in order to use the Viewdata object, I'm asked to cast the Viewdata to a type. But, I do not know how to determine the type to do the casting.
====================
EDIT
Instead of the ViewData's Model property, I'm using simply the ViewData["products"]. To retrieve the content, I just place a IEnumerable cast before the ViewData, like this:
<% foreach(var item in (IEnumerable)ViewData["products"]){%>
<p><% = Html.Encode(item)%><p>
<%}%>
There are 2 situations:
1) If I select only one column (for instance, Name), everything work fine.
2) If I select more than 1 more columns (Name, Price), I get something like this
{Name=Soccer, Price=19.50}
{Name=Shin Pads, Price=11.59}
Why I just don't get something like
Soccer, 19.50
Shin Pads, 11.59
=================================
EDIT April 02 - 05h47 AM
I've define the GetPropertyValue Method (as your response suggets) as static in a static Class that I called 'HelperClass'. Now, this is the way I try to access the value of Name from my object.
<% = Html.Encode(HelperClass.GetPropertyValue(ViewData["product"], "Name")) %>
I get the following Exception:"Object reference not set to an instance of an object". And, the following line from the inside GetPropertyValue() his highlight.
Line 22: return propInfo.GetValue(obj, null);
Do I need to use new keyword? (where?)
Thanks for helping
Private Sub filter()
Dim coll = db.Products.Where(Function(x) x.Category.Equals("Soccer")) _
.Select(Function(x) GetObject(x.Name, x.Price))
End Sub
Private Function GetObject(ByVal name As String, ByVal price As String) As Object
Return new ProductInfo(name, price)
End Function
1) To generate a new projection type at runtime you can:
.Select("new(Name, Price)")
2) To read values from the object, you need to use reflection:
string name = GetPropertyValue(someObject, "Name");
...
public static object GetPropertyValue(object obj, string propName)
{
System.Reflection.PropertyInfo propInfo = obj.GetType().GetProperty(propName);
return propInfo.GetValue(obj, null);
}

how do i display query result in view?

I am using MVC RC2.
I have Two tables
1)Product (PID, PName, CIDfk);
2)Category(CID, CName);
So i query like these
var Product = from p in dc.Product
from C in dc.Category
where p.CIDfk == c.CID
select new { ProductName = p.PName, ProductCategory = c.CName };
return view();
where dc is database context of LINQ-to-SQL class (.dbml);
How do i display in view? where i pass Product? (in viewdata or in 'return view()')
Please help me out...
You can both use:
- ViewData["MyName"] = product.SingleOrDefault();
This way from the view you'd do:
<% Product p = (Product)ViewData(p) %>
or populate the model:
ViewData.Model = product.SingleOrDefault();
This way from the view you'd do:
<%Product p = ViewData.Model%> //in case of a Strongly typed view
<%Product p = (Product)ViewData.Model%> //otherwise
After populating either ViewData or the Model you can call:
return View();
Another approach is calling the View overload that accepts the model as parameter, as tvanfosson said.
You want to have a strongly typed view and pass the product as the view model
var product = from p in dc.Product
from C in dc.Category
where p.CIDfk == c.CID
select p;
return View( product );
where your view is of type ViewPage<Product>.

Resources