I learn about making a tree view model etc , in this purpose I am making the following example
Model Tree.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace TreeTry1.Models
{
public class Tree
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int? Parent_Id { get; set; }
[ForeignKey("Parent_Id")]
public virtual ICollection<Tree> Group { get; set; }
}
}
Controller:
public ViewResult Show()
{
var roots = db.Tree.Where(r => r.Parent_Id == null);
return View(roots);
}
View
#model IEnumerable<TreeTry1.Models.Tree>
#{
Layout = null;
}
#foreach(var item in Model){
<li>
#item.Name
#if (item.Group.Count > 0)
{
<ul>
#{Html.RenderPartial("~/Views/Tree/TreeItem.cshtml", item.Group);}
</ul>
}
</li>
}
Partial View
#model IEnumerable<TreeTry1.Models.Tree>
<ul>
#Html.Partial("~/Views/Tree/TreeItem.cshtml")
</ul>
For now I recive error:
Error 1 The name 'db' does not exist in the current context
I thought that by making those classes (up) it will automatically create a database and entitiy models for that? If not then what should I do?
Do I need SQL Server for that? Or can I do it with MDF Database?
Thanks in advance for answers
YES you need a SqlServer database for that... EntityFramework is just an access layer to the underlying DB, it does not provide DB functionality by itself.
And regarding your "db not found" problem, the answer is quite obvious: where in your code did you define the variable db? no where. Visual Studio can generate the DatabaseContext class for you using database first, model first or code first. After that you'll initialize that instance in your controller like:
DatabaseContext db = new DatabaseContext();
Now the compiler knows what db is referring to!
Related
Got this error when I launch my 'Details' inside my Index on 'Firmas' (Generic auto-generated MS code):
Error
This is my model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using actiTest2.Context;
using System.Data.Entity;
namespace actiTest2.Models
{
public class PcontacFirmasModel
{
public Pcontac pcontac { get; set; }
public Firmas firmas { get; set; }
}
}
An the only call that I try to do atm:
#model actiTest2.Models.PcontacFirmasModel
#{
ViewBag.Title = Html.DisplayFor(model => model.firmas.NOMCOMP);
}
It seems that in the controller side, you are passing an object of type "Firmas" but your view is expecting the object "PcontacFirmasModel".
Update your action to send the PcontacFirmasModel object. you can use a mapper utility to map PcontacFirmasModel and Firmas.
My problem occurs when I try to tell the view which model to use. It only happens with this model though.. Here is the model code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Com.Domain.Entities
{
public class Components
{
}
public class headerModel
{
public virtual String title { get; set; }
public virtual String subtitle { get; set; }
}
}
In the view when I try to add it like this
#model Com.Domain.Entities.headerModel;
It gives me this error:
only assignment call increment decrement and new object expressions can be used as a statement
I'm not sure what's going on. Any help would be appreciated! Thanks!
Remove ; at the end of the model declaration in your view
#model Com.Domain.Entities.headerModel
I'm working on a website, where I need to retrieve pricelists, from another database on the same SQL Server as my Umbraco database.
It's a requirement that it has to be in a separate database.
I have made a new connection string Pricelist and used EF database-first.
PriceList repository:
namespace UmbracoCMS.Repository{
using System;
using System.Collections.Generic;
public partial class Prisliste
{
public string Kode { get; set; }
public string Speciale { get; set; }
public string Ydelsesgruppe { get; set; }
public string Gruppe { get; set; }
public string Ydelse { get; set; }
public string Ydelsestekst { get; set; }
public string Anaestesi { get; set; }
public string Indlæggelse { get; set; }
public Nullable<double> Listepris { get; set; }
public Nullable<int> WebSort { get; set; }
public string YdelsesTekstDK { get; set; }
public string Frapris { get; set; }
public Nullable<int> Sortering { get; set; }
}
}
PriceListController class:
using System;
using System.Linq;
using System.Web.Mvc;
using UmbracoCMS.Repository;
namespace UmbracoCMS.Controllers{
public class PriceListController : Umbraco.Web.Mvc.SurfaceController {
[HttpGet]
public PartialViewResult GetPriceList(string contentTitle){
var db = new PricelistContext();
var query = from b in db.Prislistes orderby b.Speciale select b;
Console.WriteLine("records in the database:");
foreach (var item in query)
{
Console.WriteLine(item.Speciale);
}
return PartialView("~/views/partials/PriceList.cshtml");
}
}
}
What I want is to load the prices for a treatment, based on a property on the document type. I'm just not sure how do this in umbraco since I'm fairly new a umbraco.
So when a treatment page is requested, I need to take the property ContentTitle value. Use it to retrieve all records with the same Speciale and display them in a list/table.
With a query
.where(b.Speciale = contentTitle)
It would be great if someone could help a little, or lead me in the right direction.
Also is it possible to do it in the same http request? Or should I use partial view or macros to both get the properties of the document type, from the umbraco database, and the records from the pricelist database at the same time when a user go to the treatment page?
Or is there a better way to do this?
Update:
Thanks a lot, for the great answer Ryios.
I got a question more.
using System;
using System.Linq;
using System.Web.Mvc;
namespace UmbracoCMS.Controllers
{
public class PriceListSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
public ActionResult GetPriceList(string contentTitle)
{
PricelistContext.RunInContext(db =>
{
var result = db.Prislistes.OrderBy(p => p.Speciale);
});
return View(result);
}
}
}
I got it working, so it call the method and the data from the Pricelist Database is shown in:
var result = db.Prislistes.OrderBy(p => p.Speciale);
Now I just need to get the list of prices out to the view again, so I can show a list or table of the prices.
Do you have a suggestion on how I can this in Umbraco. Normally I would return a ViewModel in MVC like:
return View(new ListViewModel(result));
and use it in the view like:
#model Project.ViewModels.ListViewModel
So I can loop through it.
But I want to still have the properties from the the "Home"/"TreatmentPage" Document type.
Should I do it with a partialView or is there a better way?
Solved
I thought I wanted to share it, if anyone else is in a similar situaction.
Controller:
namespace UmbracoCMS.Controllers
{
public class PriceListSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
public PartialViewResult PriceList(string contentTitle)
{
List<Prisliste> result = null;
PricelistContext.RunInContext(db =>
{
result = db.Prislistes.Where(p => p.Speciale == contentTitle)
.OrderBy(p => p.Speciale).ToList();
});
var model = result.Select( pl => new PrislistVm()
{
Speciale = pl.Speciale,
Listepris= pl.Listepris
});
return PartialView(model);
}
}
}
ViewModel:
namespace UmbracoCMS.ViewModels
{
public class PrislistVm
{
public PrislistVm()
{
Results = new List<Prisliste>();
}
public List<Prisliste> Results { get; set; }
public string Speciale { get; set; }
public double listepris { get; set; }
}
}
View/PriceListSurface:
#model IEnumerable<UmbracoCMS.ViewModels.PrislistVm>
#{
ViewBag.Title = "PriceList";
}
<h2>PriceList</h2>
#foreach (var item in Model)
{
#item.Speciale
#item.Listepris
}
Your going to have a memory leak if you load your EF context like that. I recommend creating a method to wrap it for you with a llambda callback. Put it in your context class.
public static void RunInContext(Action<PricelistContext> contextCallBack)
{
PricelistContext dbContext = null;
try
{
dbContext = new PricelistContext();
contextCallBack(dbContext);
}
finally
{
dbContext.Dispose();
dbContext = null;
}
}
//Example Call
PricelistContext.RunInContext(db => {
var result = db.PrisListes.OrderBy(p => p.Speciale);
//loop through your items
});
To get the Value of the DocumentType, it depends on the calling context. Assuming you are using a Razor Template that is attached to the document type, that is associated with a Content Page.
#inherits Umbraco.Web.Mvc.UmbracoTemplatePage
#{
Layout = "ContentPageLayout.cshtml";
}
#* Call GetPriceList on PriceListController with Parameter contentTitle *#
#Html.Action("GetPriceList", "PriceListSurface", new { contentTitle = Model.Content.GetPropertyValue<string>("ContentTitle") });
In the above example, I have created a document type with a property called ContentTitle that is associated with a view called ContentPage. Then I created content in the backoffice Content section called "Home" that uses the document type. Giving me a url like
http://localhost/home
Also, your SurfaceController will not work. Umbraco's logic for mapping the routes for surface controllers has some requirements for your surface controller's naming conventions. You have to end the name of the class with "SurfaceController" and then it get's called PriceListSurfaceController, then it maps the controller with a name of "PriceListSurface".
Here's the documentation for the SurfaceController features.
http://our.umbraco.org/documentation/Reference/Mvc/surface-controllers
Using a surface controller is the right logic. It's not good practice to have your Data Layer code calls in the UmbracoTemplatePage. 1, because RazorTemplates are interpreted/compiled and SurfaceController's are JIT compiled int the dll, so SurfaceController code is WAY faster. 2 Because you can make asynchronous Controller calls in MVC Razor. If it was all in the view it would make it really difficult to convert everything to be asynchronous. It's best to keep server side logic in a controller.
Optionally, you can Hijack an Umbraco route and replace it with a custom controller that doesn't have to inherit from SurfaceController, which makes it possibly to surface content to the browser that is or isn't part of umbraco.
http://our.umbraco.org/documentation/Reference/Mvc/custom-controllers
You can also create a new section in the backoffice to manage your Price List "the ui framework for building one is written against AngularJS"
http://www.enkelmedia.se/blogg/2013/11/22/creating-custom-sections-in-umbraco-7-part-1.aspx
I will try to get straight to the point. I had some help building a ViewModel here on StackOverflow. It worked fine in MVC 4 but now that I am converting the application to MVC 5 it is not working. Nothing has changed in way of the code. I have a _navigation.cshtml which is a partial that is rendered in my Layout.cshtml and the error is within the For Loops in that Partial. This same code is working fine in MVC 4. Here is the code:
My error is in the partial page during the for loop and I get the error on Ingredient in the line:
#foreach (Ingredient ingredient in Model.Ingredients)
also in the same place on any other for loop in the same place. The error says:
The type or namespace name 'Recipe' could not be found (are you
missing a using directive or an assembly reference?)
Here is my code:
Models/Ingredient.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace XXX.Models
{
public class Ingredient
{
public int IngredientID { get; set; }
public string IngredientNameEs { get; set; }
}
}
Models/Recipe.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace XXX.Models
{
public class Recipe
{
public int RecipeID { get; set; }
public string RecipeNameEs { get; set; }
}
}
Models/IdentityModel.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Linq;
using System.Web;
using Microsoft.AspNet.Identity.EntityFramework;
using XXX.Models;
namespace XXX.Models
{
// You can add profile data for the user by adding more properties to your ApplicationUser class,
// http://go.microsoft.com/fwlink/?LinkID=317594 for more.
public class ApplicationUser : IdentityUser
{
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(): base("DefaultConnection")
{
}
public DbSet<Ingredient> Ingredients { get; set; }
public DbSet<Recipe> Recipes { get; set; }
}
}
ViewModels/NavigationViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using XXX.Models;
namespace XXX.ViewModels
{
public class NavigationViewModel
{
public IEnumerable<Ingredient> Ingredients { get; set; }
public IEnumerable<Recipe> Recipes { get; set; }
}
}
Controllers/PartialsController.cs
using XXX.Models;
using XXX.ViewModels;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace XXX.Controllers
{
public class PartialController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
public ActionResult Navigation()
{
NavigationViewModel viewModel;
viewModel = new NavigationViewModel();
viewModel.Ingredients = db.Ingredients.Where(i => i.IsProduct != false).ToList();
viewModel.Recipes = db.Recipes.ToList();
return PartialView("_Navigation", viewModel);
}
}
}
Partials/_Navigation.cshtml (Asterisks indicate error near Ingredient and Recipe in For Loop)
#model XXX.ViewModels.NavigationViewModel
#using XXX.Models
//edited for brevity..
<li class="has-dropdown">#Html.ActionLink(XXX.Views.Shared.CultureSwap.Products, "Products", "Ingredient")
<ul class="dropdown">
#*//From NavigationViewModel print out each Product*#
#foreach (*Ingredient* ingredient in Model.Ingredients)
{
<li>#ingredient.IngredientNameEs</li>
}
</ul>
</li>
<li class="divider"></li>
<li class="has-dropdown">#Html.ActionLink(XXX.Views.Shared.CultureSwap.Recipes, "List", "Recipe")
<ul class="dropdown">
#foreach (*Recipe* recipe in Model.Recipes)
{
<li>#recipe.RecipeNameEs</li>
}
</ul>
</li>
Again the errors read:
The type or namespace name 'Ingredient' could not be found (are you
missing a using directive or an assembly reference?)
The type or namespace name 'Recipe' could not be found (are you
missing a using directive or an assembly reference?)
Here is a screenshot of the error in Visual Studio Next to the same code with no errors:
There is a web.config file located in the Views directory. In it the namespaces that should be available for the views are listed. Did you add a namespace to the views web.config in your mvc4 proj that you are now missing in the mvc5 proj?
The listing in the views web.config is a kind of global using statements that applies to all views.
Your view doesn't know where Ingredient or Recipe come from, you need to add a reference to the namespace which those types are under, add #using XXX.Models to the top of your view
#model XXX.ViewModels.NavigationViewModel
#using XXX.Models
...
#foreach (Ingredient ingredient in Model.Ingredients)
{
...
}
On a side-note you appear to have a half-baked view model implementation. In your NavigationViewModel you are referencing, which appear to be, domain models. It's generally recommended that anything exposed via a view model, is in actual fact, a view model itself. So in your case, I would introduce a couple of new view models to represent an Ingredient / Recipe i.e.
public class IngredientViewModel
{
...
}
public class RecipeViewModel
{
...
}
public class NavigationViewModel
{
public IEnumerable<IngredientViewModel> Ingredients { get; set; }
public IEnumerable<RecipeViewModel> Recipes { get; set; }
}
These would be be created under the XXX.ViewModels which would mean your view would look like
#using XXX.ViewModels
#model NavigationViewModel
...
Your view doesn't know where Ingredient or Recipe come from, you need to add a reference to the namespace which those types are under, add #using XXX.Models to the top of your view.
If your MVC application has Areas, check whether the namespace of the ViewModel and model reference in the Razor view is matched or not.
If the namespace of the view model contains Areas e.g. Areas.WebApp.Models , that view model won't be compiled in the view when you write #model WebApp.Models.
Both should match. So either remove Areas from ViewModel namespace or add the same fully qualified name in the View.
I know that this Question is asked so many times. I have read and implemented all solution but didn't get success. I am getting this error when I retrieve data from database using EF and binds with model after that use this model on View.
My controller code is
using System.Linq;
using System.Web.Mvc;
using JsonRenderingMvcApplication.Models;
namespace JsonRenderingMvcApplication.Controllers
{
public class PublisherController : Controller
{
public ActionResult Index()
{
PublisherModel model = new PublisherModel();
using (DAL.DevelopmentEntities context = new DAL.DevelopmentEntities())
{
model.PublisherList = context.Publishers.Select(x =>
new SelectListItem()
{
Text = x.Name,
Value = x.Id.ToString()
}); ;
}
return View(model);
}
}
}
My View code is
#model JsonRenderingMvcApplication.Models.PublisherModel
#{
ViewBag.Title = "Index";
}
<div>
#Html.DisplayFor(model=>model.Id)
#Html.DropDownListFor(model => model.Id, Model.PublisherList);
</div>
<div id="booksDiv">
</div>
My model code is
using System.Collections.Generic;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;
namespace JsonRenderingMvcApplication.Models
{
public class PublisherModel
{
public PublisherModel()
{
PublisherList = new List<SelectListItem>();
}
[Display(Name="Publisher")]
public int Id { get; set; }
public IEnumerable<SelectListItem> PublisherList { get; set; }
}
}
My entity code is
namespace JsonRenderingMvcApplication.DAL
{
using System;
using System.Collections.Generic;
public partial class Publisher
{
public Publisher()
{
this.BOOKs = new HashSet<BOOK>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Year { get; set; }
public virtual ICollection<BOOK> BOOKs { get; set; }
}
}
Yes this entity has a navigation property but I don't want to that entity data so I don't want to include that.
Thanks
The problem you're experiencing is due to LINQ's deferred execution. It's quite the gotcha for developers who haven't yet realized how LINQ works under the hood. I have a great blog post about it, but the core concept is that you must force an enumeration on the collection to cause the LINQ code to run immediately instead of later. This means changing this:
model.PublisherList = context.Publishers.Select(x =>
new SelectListItem()
{
Text = x.Name,
Value = x.Id.ToString()
});
to this:
model.PublisherList = context.Publishers.Select(x =>
new SelectListItem()
{
Text = x.Name,
Value = x.Id.ToString()
}).ToList();
Note the .ToList() there which forces the enumeration.
Your LINQ query is deferred meaning that it is not being run at your controller but instead afterwards, probably in your view where you loop over the collection (which forces the enumeration and thus runs the LINQ). Because you're using the using statement to dispose of your DB context (which is of course good practice), the context is disposed of before you reach the view, which executes the code against the disposed context. Forcing the enumeration within the using statement will run the code at that time, instead of later when the context is disposed, and prevent this issue.