I have a simple application which should display the elements of a list, but it returns an empty array when debugging. I need this elements to be displayed dinamically. I'm wondering if the program is not working because of the following code...
StoreController.cs
using GetMed.Models;
namespace GetMed.Controllers
{
public class StoreController : Controller
{
GetMedEntities storeDB = new GetMedEntities();
//
// GET: /Store/
public ActionResult Index()
{
var categories = storeDB.Categories.ToList();
return View(categories);
}
}
}
SampleData.cs:
using System.Data.Entity;
namespace GetMed.Models
{
public class SampleData : DropCreateDatabaseIfModelChanges<GetMedEntities>
{
protected override void Seed(GetMedEntities context)
{
var categories = new List<Category>
{
new Category { Name = "Infections" },
new Category { Name = "Antibiotics" },
new Category { Name = "Vitamins" },
new Category { Name = "Cosmetics" }
};
}
}
}
GetMedEntities.cs
namespace GetMed.Models
{
public class GetMedEntities : DbContext
{
public DbSet<Category> Categories { get; set; }
}
}
Index.cs:
#model IEnumerable<GetMed.Models.Category>
#{
ViewBag.Title = "Index";
}
<h3>Browse Categories</h3>
<p>Select from #Model.Count() categories:</p>
<ul>
#foreach (var category in Model)
{
<li>#Html.ActionLink(category.Name, "Browse", new { category = category.Name })</li>
}
</ul>
If you look at your database, you will notice that there is no data in it. Look at your Seed method: what do you expect it to do?
After creating your data you have two more steps to do:
Adding it to a collection tracked by your DbContext
Saving it to the database
This results in these extra lines:
context.Categories.AddRange(categories);
context.SaveChanges();
Never initialize EF context gloablly, once it gonna hit you hard, believe me
When adding records to DB via EF you have to call
using (var context = new GetMedEntities)
{
// YOUR ADD ROUTINE GOES HERE
context.SaveChanges();
}
UPDATE
Change your class SampleData
public class SampleData : DropCreateDatabaseIfModelChanges<GetMedEntities>
{
protected override void Seed(GetMedEntities context)
{
//I STRICTLY RECOMMEND NOT TO PROVIDE CONTEXT AS A METHOD PARAMETER
//YOU HAVE TO WRITE PROPER DB LAYER TO DO SO
context.Categories.AddRange( new List<Category>()
{
new Category { Name = "Infections" },
new Category { Name = "Antibiotics" },
new Category { Name = "Vitamins" },
new Category { Name = "Cosmetics" }
});
context.SaveChanges();
}
}
But the simple solution is the following:
public class SampleData
{
public void SeedSampleData()
{
var context = new GedMedEntities();
context.Categories.AddRange( new List<Category>()
{
new Category { Name = "Infections" },
new Category { Name = "Antibiotics" },
new Category { Name = "Vitamins" },
new Category { Name = "Cosmetics" }
});
context.SaveChanges();
Related
I am following a tutorial on the documentation to try create my own database. The data was seeding properly with 3 tables and now I have added 6 I can't get the data to seed. I have tried creating a migration and updating the database. I did change some of the ON DELETE CASCADE to ON DELETE NO ACTION as I was getting an error with cascading and I am not sure if that is the reason that it isn't seeding.
For reference it was the tables 'Car' , 'PaymentPlan' & 'SalesMan' that was working previously
Initialise code:
using GarageSales.Data;
using GarageSales.Models;
using System;
using System.Linq;
namespace GarageSales.Data
{
public static class DbInitializer
{
public static void Initialize(GarageSalesContext context)
{
//context.Database.EnsureCreated();
// Look for any Cars.
if (context.Cars.Any())
{
return; // DB has been seeded
}
var Customers = new Customer[]
{
new Customer{FirstName="Ray", LastName="Easton", Gender="Male", Address="2 Church Road", PostCode="BT35 0JW", RentalID=1, CarID=1, SalesManID=1},
new Customer{FirstName="Amelie", LastName="Bush", Gender="Female", Address="54 Beach Gardens", PostCode="BT34 0JE", RentalID=2, CarID=2, SalesManID=2},
new Customer{FirstName="Ray", LastName="Easton", Gender="Male", Address="2 Church Road", PostCode="BT67 0JW", RentalID=3, CarID=3, SalesManID=3}
};
foreach (Customer customer in Customers)
{
context.Customer.Add(customer);
}
context.SaveChanges();
var Cars = new Car[]
{
new Car{Model="I8",Manufacturer="BMW",EngineSize="1.5 L 3-cylinder"},
new Car{Model="A5",Manufacturer="Audi",EngineSize="5.2 L V10"},
new Car{Model="R8",Manufacturer="Audi",EngineSize="1.5 L 3-cylinder"}
};
foreach (Car car in Cars)
{
context.Cars.Add(car);
}
context.SaveChanges();
var SalesMen = new SalesMan[]
{
new SalesMan{FirstName="Darren",SurName="Dooning"},
new SalesMan{FirstName="Jim",SurName="Campbell"},
new SalesMan{FirstName="Jade",SurName="Mull"},
};
foreach (SalesMan SalesMan in SalesMen)
{
context.SalesMen.Add(SalesMan);
}
context.SaveChanges();
var Rentals = new Rental[]
{
new Rental{Price=150, Duration=36, Quote=3500, CustomerID=1, CarID=1, SalesManID=1},
new Rental{Price=200, Duration=24, Quote=2000, CustomerID=2, CarID=2, SalesManID=2},
new Rental{Price=400, Duration=12, Quote=4500, CustomerID=3, CarID=3, SalesManID=3}
};
foreach (Rental Rental in Rentals)
{
context.Rental.Add(Rental);
}
context.SaveChanges();
var PaymentPlans = new PaymentPlan[]
{
new PaymentPlan{CarID=1,SalesManID=1},
new PaymentPlan{CarID=2,SalesManID=2},
new PaymentPlan{CarID=3,SalesManID=3}
};
foreach (PaymentPlan PaymentPlan in PaymentPlans)
{
context.PaymentPlans.Add(PaymentPlan);
}
context.SaveChanges();
var Duration = new Duration[]
{
new Duration{DurationLength=36, RentalID=1, SalesManID=1},
new Duration{DurationLength=24, RentalID=2, SalesManID=2},
new Duration{DurationLength=12, RentalID=3, SalesManID=3}
};
foreach (Duration duration in Duration)
{
context.Duration.Add(duration);
}
context.SaveChanges();
}
}
}
Context class (The dataSets are 2 different ways as I figured late on and would have to go and change it to make the program run):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using GarageSales.Models;
namespace GarageSales.Data
{
public class GarageSalesContext: DbContext
{
public GarageSalesContext (DbContextOptions<GarageSalesContext> options)
: base(options)
{
}
public DbSet<Car> Cars { get; set; }
public DbSet<PaymentPlan> PaymentPlans { get; set; }
public DbSet<SalesMan> SalesMen { get; set; }
public DbSet<GarageSales.Models.Customer> Customer { get; set; }
public DbSet<GarageSales.Models.Duration> Duration { get; set; }
public DbSet<GarageSales.Models.Rental> Rental { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Car>().ToTable("Car");
modelBuilder.Entity<PaymentPlan>().ToTable("PaymentPlan");
modelBuilder.Entity<SalesMan>().ToTable("SalesMan");
modelBuilder.Entity<Duration>().ToTable("Duration");
modelBuilder.Entity<Rental>().ToTable("Rental");
modelBuilder.Entity<Customer>().ToTable("Customer");
}
}
}
If you need anymore information just ask
I am creating a test project where i have products, i didn't won't to use a database at the beginning so i made Mocks Data that returns a list of products, but i want a user should be able to add to the list.
This is the Model
namespace StoreTest.Models
{
public class Products
{
public int Id { get; set; }
public string Name { get; set; }
public double Price { get; set; }
}
}
This is the Mock data class
using System.Collections.Generic;
using StoreTest.Models;
namespace StoreTest.Data.Mocs
{
public class ProductMocks
{
public IList<Products> ProductList
{
get
{
return
new List<Products>
{
new Products
{
Id = 1,
Name = "Some Data",
Price = 34.00
},
new Products
{
Id = 2,
Name = "More Data",
Price = 28.00
}
};
}
}
}
}
This is the part from the Controller where i want to add to the ProductList
[HttpPost]
public IActionResult NewProduct(NewProductViewModel vm)
{
if (ModelState.IsValid)
{
Products product = new Products()
{
Id = vm.Id,
Name = vm.Name,
Price = vm.Price
};
ProductMocks addProduct = new ProductMocks();
// THIS IS NOT WORKING
productMocs.ProductList.Add(product);
return View("Index", addProduct);
}
else
{
return View(vm);
}
}
I am very new to asp.net.
Idon't know if i need to change the whole ProductMocks class, or i only need to add something in the controller?
Thank you in advanced!
Your ProductMocks implementation is not correct, as when you access the ProductList property every time get is called and as a result a new object is created so the object in which you add is lost in the memory somewhere.
Change your class to be :
public class ProductMocks
{
public ProductMocks()
{
ProductList = new List<Products>
{
new Products
{
Id = 1,
Name = "Some Data",
Price = 34.00
},
new Products
{
Id = 2,
Name = "More Data",
Price = 28.00
}
};
}
public IList<Products> ProductList
{
get;
set;
}
}
Now setting the values in constructor that are needed at start, and now you can add as needed on the instance you created in Controller.
or another way would be to have a backing field yourself and check it, if it is null then create instance with default values else return the instance as it is without creating another new one :
public class ProductMocks
{
private IList<Products> _ProductList;
public IList<Products> ProductList
{
get
{
if(_ProductList == null)
{
_ProductList = new List<Products>
{
new Products
{
Id = 1,
Name = "Some Data",
Price = 34.00
},
new Products
{
Id = 2,
Name = "More Data",
Price = 28.00
}
};
}
return _ProductList;
}
}
}
But the second approach might result in unexpected behaviors for the callers, as in cases where they would expect ProductList to be null will have two items in it and not null.
Hope it Helps.
Ill keep the question short, as i suspect the answer may be a short no..
I would like to be able to pass a query into an entity framework function, to enable dynamic runtime querying through the ui to the database?
I imagined this to be like passing an IQueryable into a method, but exactly how i would go about this, i am a little unsure at the moment. Am i thinking about this the wrong way? Perhaps querying in the business layer, not semi-directly to the database?
Based on the comments, I'm providing the two options.
Based on a set of options given to the user.
Use a TreeExpression to build you expression dynamically, somthing like the example above (this example is indeed too simple, but you can have an idea).
ParameterExpression numParam = Expression.Parameter(typeof(int), "num");
ConstantExpression five = Expression.Constant(5, typeof(int));
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
Expression<Func<int, bool>> lambda1 = Expression.Lambda<Func<int, bool>>(numLessThanFive, new ParameterExpression[] { numParam });
This link will give you some more info on the subject: https://msdn.microsoft.com/en-us/library/bb882637.aspx
For letting the user type some expression and converting it to a query, search for Antlr http://www.antlr.org/, or some tool like this, padronize the expression syntax you want to implement and go for the 1ยบ solution to build the expression.
My example code is below. You'll need to install the following packages...
install-package entityframework
install-package newtonsoft.json
Be aware that this code is susceptible to injection by inserting valid VB.NET code to escape the query.
I compiled the code into 30742268.exe, which you can see is added as a reference for the IContext interface, etc.
using System;
using System.Linq;
using System.Text;
using Microsoft.VisualBasic;
using System.CodeDom.Compiler;
using Model;
using System.Collections.Generic;
using System.Data.Entity;
using Newtonsoft.Json;
namespace _30742268 {
class Program {
const String queryWrapperCode = #"
Imports System.Linq
Imports System.Data.Entity
Imports Model
Public Class DynamicQuery
Implements IDynamicQuery
Public Function Run(data As IContext) As IQueryable Implements IDynamicQuery.Run
Return {0}
End Function
End Class
";
static void Main(String[] args) {
using (var provider = new VBCodeProvider()) {
var parameters = new CompilerParameters();
parameters.ReferencedAssemblies.Add("System.Core.dll");
parameters.ReferencedAssemblies.Add("EntityFramework.dll");
parameters.ReferencedAssemblies.Add("30742268.exe");
parameters.GenerateInMemory = true;
Console.WriteLine("Enter LINQ queries, 'demo' for an example, 'exit' to stop:");
for (;;) {
try {
var dynamicQueryString = Console.ReadLine();
if (dynamicQueryString == "exit")
return;
if (dynamicQueryString == "demo")
Console.WriteLine(dynamicQueryString = "from person in data.People where person.Name.Length = 4");
var results = provider.CompileAssemblyFromSource(parameters, String.Format(queryWrapperCode, dynamicQueryString));
if (results.Errors.HasErrors) {
var sb = new StringBuilder();
foreach (CompilerError error in results.Errors) {
sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
}
throw new InvalidOperationException(sb.ToString());
}
var assembly = results.CompiledAssembly;
var assemblyType = assembly.GetTypes().Single(x => typeof (IDynamicQuery).IsAssignableFrom(x));
var constructorInfo = assemblyType.GetConstructor(new Type[] {});
var dynamicQuery = (IDynamicQuery) constructorInfo.Invoke(null);
using (var context = new Context()) {
dynamic result = dynamicQuery.Run(context);
foreach (var person in result)
Console.WriteLine(person);
}
}
catch (Exception exception) {
Console.WriteLine(exception);
}
}
}
}
}
}
namespace Model {
public interface IDynamicQuery {
IQueryable Run(IContext context);
}
public abstract class Entity {
public override String ToString() {
return JsonConvert.SerializeObject(this, Formatting.Indented, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
}
}
public class Person : Entity {
public Int64 Id { get; protected set; }
public String Name { get; set; }
public virtual Home Home { get; set; }
}
public class Home : Entity {
public Int64 Id { get; protected set; }
public String Address { get; set; }
public virtual ICollection<Person> Inhabitants { get; set; }
}
public interface IContext {
IQueryable<Person> People { get; set; }
IQueryable<Home> Homes { get; set; }
}
public class Context : DbContext, IContext {
public virtual DbSet<Person> People { get; set; }
public virtual DbSet<Home> Homes { get; set; }
IQueryable<Person> IContext.People {
get { return People; }
set { People = (DbSet<Person>)value; }
}
IQueryable<Home> IContext.Homes {
get { return Homes; }
set { Homes = (DbSet<Home>)value; }
}
public Context() {
Configuration.ProxyCreationEnabled = false;
Database.SetInitializer(new ContextInitializer());
}
}
class ContextInitializer : DropCreateDatabaseAlways<Context> {
protected override void Seed(Context context) {
var fakeSt = new Home {Address = "123 Fake St."};
var alabamaRd = new Home {Address = "1337 Alabama Rd."};
var hitchhikersLn = new Home {Address = "42 Hitchhiker's Ln."};
foreach (var home in new[] {fakeSt, alabamaRd, hitchhikersLn})
context.Homes.Add(home);
context.People.Add(new Person { Home = fakeSt , Name = "Nick" });
context.People.Add(new Person { Home = fakeSt , Name = "Paul" });
context.People.Add(new Person { Home = fakeSt , Name = "John" });
context.People.Add(new Person { Home = fakeSt , Name = "Henry" });
context.People.Add(new Person { Home = alabamaRd , Name = "Douglas" });
context.People.Add(new Person { Home = alabamaRd , Name = "Peter" });
context.People.Add(new Person { Home = alabamaRd , Name = "Joshua" });
context.People.Add(new Person { Home = hitchhikersLn, Name = "Anne" });
context.People.Add(new Person { Home = hitchhikersLn, Name = "Boris" });
context.People.Add(new Person { Home = hitchhikersLn, Name = "Nicholes" });
context.People.Add(new Person { Home = hitchhikersLn, Name = "Betty" });
context.SaveChanges();
}
}
}
I'm working on an asp.net mvc project where I've created a partial view with some dropdowns. These are populated with ajax, and should work as a filter. (Not really relevant to my question, I guess, but nice to know anyhow).
A problem occurrs when trying to invoke the partial view, saying the following:
An error occurred when trying to create a controller of type 'Project.Name.Web.Controllers.PlanFilterController'. Make sure that the controller has a parameterless public constructor.
However, my controller does appear to have a parameterless constructor;
public class PlanFilterController : BaseController
{
public PlanFilterControllerViewModel Model { get; set; }
public List<DropDownItem> Items { get; set; }
public List<ProjectContract> AllProjects { get; set; }
public List<CustomerContract> AllCustomers { get; set; }
public List<UnitContract> AllUnits { get; set; }
private ProjectServiceClient ProjectClient { get; set; }
private CustomerServiceClient CustomerClient { get; set; }
public PlanFilterController()
{
AllProjects = new List<ProjectContract>();
AllCustomers = new List<CustomerContract>();
AllUnits = new List<UnitContract>();
ProjectClient = new ProjectServiceClient();
CustomerClient = new CustomerServiceClient();
AllProjects = ProjectClient.GetProjects().ToList();
AllCustomers = CustomerClient.GetCustomers().ToList();
AllUnits = UnitClient.GetUnits(true, "", false).ToList();
}
// GET: /PlanFilter/
[ChildActionOnly]
public ActionResult FilterControl()
{
return PartialView();
}
// Populate dropdowns
public JsonResult GetCascadeCustomers()
{
Items = new List<DropDownItem>();
foreach (var customer in AllCustomers)
{
Items.Add(new DropDownItem
{
ItemId = customer.Id,
ItemName = customer.Name
});
}
return Json(Items, JsonRequestBehavior.AllowGet);
}
public JsonResult GetCascadeProjects()
{
Items = new List<DropDownItem>();
foreach (var project in AllProjects)
{
Items.Add(new DropDownItem
{
ItemId = project.Id,
ItemName = project.Name
});
}
return Json(Items, JsonRequestBehavior.AllowGet);
}
public JsonResult GetCascadeUnits()
{
Items = new List<DropDownItem>();
foreach (var unit in AllUnits)
{
Items.Add(new DropDownItem
{
ItemId = unit.Id,
ItemName = unit.Name
});
}
return Json(Items, JsonRequestBehavior.AllowGet);
}
}
What am I missing here? Also, if someone could please provide the explanation to why this is the case, that would be nice :)
As mentioned in comments, something had happened when I added my service references, and some code was not automatically generated. This again caused the exception mentioned.
I'm trying to display some information from a model to my view in Nancy.
Viewmodel
public class Fixtures
{
public int Id { get; set; }
public Users HomeUser { get; set; }
public Users AwayUser { get; set; }
}
Module
Get["/fixtures"] = _ =>
{
var model = new List<Fixtures>();
model.Add(new Fixtures() { Id = 1, HomeUser = new Users() { id = 1, Name = "Paddy" }, AwayUser = new Users() { id = 2, Name = "Dave" } });
model.Add(new Fixtures() { Id = 2, HomeUser = new Users() { id = 3, Name = "Scott" }, AwayUser = new Users() { id = 4, Name = "Chris" } });
return View["Fixtures", model];
};
View
#inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<System.Collections.Generic.List<Fifa.Leaderboard.Data.ViewModel.Fixtures>>
#{
Layout = "_Layout.cshtml";
}
<div id="fixtures">
#foreach (var fixture in Model)
{'
<p>#fixture.HomeUser</p>
<p>VS</p>
<p>#fixture.AwayUser</p>
}
</div>
Anyone know why I'm getting this error?
Problem was found as mentioned in comments of original question.
Nancy does not have a concept of a Shared Views folder like ASP.NET MVC.
The normal way to do this would be to put the _Layout.cshtml in the root of the /Views folder.
If you want to avoid the view being in the root folder or avoid specifying the full path, you can add a View Location to the list like so:
public class CustomConventionsBootstrapper : DefaultNancyBootstrapper
{
protected override void ApplicationStartup(TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines)
{
this.Conventions.ViewLocationConventions.Add((viewName, model, context) =>
{
return string.Concat("views/shared/", viewName);
});
}
}
Documentation can be found here:
https://github.com/NancyFx/Nancy/wiki/View-location-conventions#defining-custom-conventions