I have a table 'Menus' containing the
names of the menus of the restaurant.
I also have a table 'Ingredients'
containing the ingredients that are
available to the menus.
I don't have any trouble getting the values out of the 'Menus' table into an IQueryable class (PropAllMenus)
Public Class PropAllMenus
Private _MenuID As Integer
Public Property MenuID() As Integer
Get
Return _MenuID
End Get
Set(ByVal value As Integer)
_MenuID = value
End Set
End Property
Private _Name As String
Public Property Name() As String
Get
Return _Name
End Get
Set(ByVal value As String)
_Name = value
End Set
End Property
Private _DaypartID As Integer
Public Property DaypartID() As Integer
Get
Return _DaypartID
End Get
Set(ByVal value As Integer)
_DaypartID = value
End Set
End Property
I just use this code in the DBRepository class
Public Function ListAllMenus() As IQueryable(Of PropAllMenus) Implements IDBRepository.ListAllMenus
Dim result = From p In _db.Menus Select New PropAllMenus With {.MenuID = p.MenuID, .Name = p.Name}
Return result
End Function
This works fine.
Now, i also have a many to many
table 'MenuIngredients' containing
the Id's of ingredients that belong
to a menu.
However, i don't know what steps i should take to:
Query the DB with a LINQ query to
get a LIST of MENU NAMES with all
their INGREDIENTS
fill up a new
IQuerable(of...) class so i can pass
it to my view
I tried using a property of type array (that contained the ingredients of a menu) but that didn't seem to work.
YOu just need to add a partial class to your current Menu class like this:
public partial class Books
public property IEnumerable< Ingredient > Ingredients
get
return me. MenuIngredients.Select( function (mi) mi.Ingredient);
end get
end Property
public sub AddIngredient( i as Ingredient )
//do the logic here
End Sub
public sub AddIngredient( i as Ingredient )
//do the logic here
End Sub
End
This then would include the ingredients in to your menu class
Related
I have a VB.NET mvc view form that has 3 parameters and 2 buttons and I not sure how to design my page.
Button 1 is essentially a GET - suppose to run a sql query and return a dataset (multiple tables).
Button 2 is essentially a PUT - suppose to run a sql update statement (multiple updates).
CustomModel includes my 3 parameters as Properties and I have included the Required Attribute on all.
How do I design so that the Required attributes are respected.
I.e. my ViewInfo method is being reached even if the parameter inputs are blank.
Do I declare ViewInfo with the HttpGet and my UpdateInfo with HttpPut attribute. Do I need the parameter declarations in my ViewInfo method?
Is my #Html.BeginForm(...) declaration correct?
VB.NET Model class:
Public Class CustomModel
<Required(ErrorMessage:="Parameter 1 is required"),
Display(Name:="Parameter 1:")>
Public Property Parameter1 As String
<Required(ErrorMessage:="Parameter 2 is required"),
Display(Name:="Parameter 2:")>
Public Property Parameter2 As String
<Required(ErrorMessage:="Parameter 3 is required"),
Display(Name:="Parameter 3:")>
Public Property Parameter3 As Integer
Public Sub New(Parameter1 As String, Parameter2 As String, Parameter3 As Integer)
Me.Parameter1 = Parameter1
Me.Parameter2 = Parameter2
Me.Parameter3 = Parameter3
End Sub
Public Property Info As DataSet = New DataSet
End Class
VB.NET Controller:
Function Index() As ActionResult
ViewBag.ShowView = False
Return View()
End Function
Function ViewInfo(Parameter1 As String, Parameter2 As String, Parameter3 As Integer)
Dim result As New CustomModel(Parameter1, Parameter2, Parameter3)
If ModelState.IsValid Then
result.Info = GetInfo(Parameter1, Parameter2, Parameter3)
End If
ViewBag.ShowView = True
Return View("Index", result)
End Function
Function UpdateInfo(Parameter1 As String, Parameter2 As String, Parameter3 As Integer)
Dim result As New CustomModel(Parameter1, Parameter2, Parameter3)
If ModelState.IsValid Then
result.Info = UpdateInfo(Parameter1, Parameter2, Parameter3)
End If
ViewBag.ShowView = True
Return View("Index", result)
End Function
HTML View
#ModelType CustomModel
...
#Using (Html.BeginForm("ViewInfo", "Home", Nothing, FormMethod.Post))
...
#Html.LabelFor(...)
#Html.TextBoxFor(...)
...
<button type=button>View</button>
<button type=submit>Update</button>
End Using
Output:
#If ViewBag.Show Then
// Multiple WebGrid calls ???
End If
I found a solution to get me on my way finally.
I did not realise the default layout page behind the scenes does not include the validation javascript file so I had to add to my specific view file:
#Section scripts
#Scripts.Render("~/bundles/jqueryval")
End Section
Is there something you have to do so that this file is automatically brought in or is what I have done is correct you have to manually include it in either the layout or the specific view where you need it?
I cant seem to figure this out, I'm not that new to the MVC model but perhaps my brain is just tired.
View Model
Public Class CategoriesViewModel
Public Property Categories As List(Of cihCategoryOrgDef)
Public Property Category As cihCategoryOrgDef
Public Property SelectedItem As String
Public Sub New(organizationId As Guid, codId As Guid)
Categories = lists.organizationClubCategories
Category = From x In Categories
Where x.codId = codId
Select x
End Sub
End Class
CategoriesController
Function Edit(codId As Guid) As ActionResult
Dim model As CategoriesViewModel = New CategoriesViewModel(ZenCommon.CurrentOrgId, codId)
Return View(model)
End Function
When I run this, I get a "invalid cast exception" on the Category = From x.... line
Unable to cast object of type 'WhereSelectListIterator`2[Library.cihCategoryOrgDef,Library.cihCategoryOrgDef]' to type 'Library.cihCategoryOrgDef'.
I'm trying to get a single Category to use in my View. So I can have an edit page for that specific category. Am I going about this all wrong?
Since Category is a single category, you need to make sure your LINQ returns a single result. If you're sure that the query will only return one value, use SingleOrDefault:
Category = (From x In Categories
Where x.codId = codId
Select x).SingleOrDefault()
If your query could return more than one result and you only want to take the first result, use FirstOrDefault:
Category = (From x In Categories
Where x.codId = codId
Select x).FirstOrDefault()
Your select actually returns a collection, that's why you get invalid cast exception. To get only one item you need something like this (sorry, I'm not very much familiar with vb, so here is c# code):
Category = (From x In Categories
Where x.codId = codId
Select x).DefaultIfEmpty(null).FirstOrDefault();
Public Function List_category() As Myobj
Dim query = From subcat In _dataContext.subcategories, _
cat In _dataContext.categories _
Where subcat.CategoryID = cat.CategoryID _
Select New Myobj() With { _
.SubcatId = subcat.SubCategoryID, _
.SubcatName = subcat.SubCategoryName, _
.CatId = cat.CategoryID, _
.CatName = cat.CategoryName _
}
return ?????????
End Function
Public Class Myobj
Private m_SubcatId As Integer
Private m_SubcatName As String
Private m_catId As Integer
Private m_catName As String
Public Property SubcatId() As Integer
Get
Return m_SubcatId
End Get
Private Set(ByVal value As Integer)
m_SubcatId = value
End Set
End Property
Public Property SubcatName() As String
Get
Return m_SubcatName
End Get
Private Set(ByVal value As String)
m_SubcatName = value
End Set
End Property
Public Property CatId() As Integer
Get
Return m_catId
End Get
Private Set(ByVal value As Integer)
m_catId = value
End Set
End Property
Public Property CatName() As String
Get
Return m_catName
End Get
Private Set(ByVal value As String)
m_catName = value
End Set
End Property
End Class
doesnt works!!!!
It Says 'Set' accessor of property 'SubcatName' is not accessible.
You can create a custom type and modify your select to instantiate that for the return. Take a look here: Linq To Sql return from function as IQueryable<T>
Compiler is just telling you that you have declared Private Set on SubcatName and yet ypou are trying to assing a value to it after New Myobj().
For a first run you can declare a POD class (plain old data - just public data, no methods or properties) and once you see it runnung you can go tweaking it, adding methods etc.
If it's really important that all properties are read-only you'll need to try making your querying method a static member of the same class.
Also, there is a way to return anonymous type and cast it back to equivalent anonymous type declared at the receiving side. Got to move on to C# though :-)
Example (read article):
// Method that returns anonymous type as object
object ReturnAnonymous()
{
return new { City="Prague", Name="Tomas" };
}
// Application entry-point
void Main()
{
// Get instance of anonymous type with 'City' and 'Name' properties
object o = ReturnAnonymous();
// This call to 'Cast' method converts first parameter (object) to the
// same type as the type of second parameter - which is in this case
// anonymous type with 'City' and 'Name' properties
var typed = Cast(o, new { City="", Name="" });
Console.WriteLine("Name={0}, City={1}", typed.Name, typed.City);
}
// Cast method - thanks to type inference when calling methods it
// is possible to cast object to type without knowing the type name
T Cast<T>(object obj, T type)
{
return (T)obj;
}
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);
}
i must be doing something wrong or maybe i don't get this. I'm trying to fill 'PropAllMenus' (that has a bunch of properties) with data coming from my entity framework. However, when doing the conversion trough a function i get a 'InvaldCastExeption' in my 'WeekMenuRepository'. Here is the code:
PropAllMenus
Public Class PropAllMenus
Private _MenuID As Integer
Public Property MenuID() As Integer
Get
Return _MenuID
End Get
Set(ByVal value As Integer)
_MenuID = value
End Set
End Property
Private _Name As String
Public Property Name() As String
Get
Return _Name
End Get
Set(ByVal value As String)
_Name = value
End Set
End Property
Private _DaypartID As Integer
Public Property DaypartID() As Integer
Get
Return _DaypartID
End Get
Set(ByVal value As Integer)
_DaypartID = value
End Set
End Property
End Class
WeekMenuRepository
Private _db As New EDMWeekmenuEntities()
Public Function ListAllMenus() As IQueryable(Of PropAllMenus) Implements IWeekMenuRepository.ListAllMenus
Dim result = From p In _db.Menus _
Select p
Return result
End Function
HomeController
Dim DoThings As New WeekMenuRepository()
Function Index() As ActionResult
Return View(DoThings.ListAllMenus().ToList)
End Function
PropAllMenus isn't an entity type, so the EF can't implicitly convert an entity type like Menu to it.
In other words, your function result type is IQueryable(Of PropAllMenus), but your query is returning something like ObjectQuery(Of Menu). If you could change your query to return ObjectQuery(Of PropAllMenus) then the implicit cast (when you call Return) to IQueryable would work.
You need to do something like:
Dim result = From p In _db.Menus _
Select New PropAllMenus With
{
.MenuId = p.MenuId,
.Name = p.Name,
// etc.
}
By the way, I noticed that you have asked 6 questions, but have never accepted any answers, nor uploaded anything. You should press the "up arrow" next to any answers which you find helpful, and press the "checkmark" icon next to the single most helpful answer for a question you've asked. It's a way of saying "thank you."