2 models(tables) inside 1 view in Asp.net MVC4 - entity-framework

I have Konu and Etiketler tables in database.
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
SonerSevincComEntities context = new SonerSevincComEntities();
var Konular = context.Konu.ToList();
return View(Konular);
}
}
In Konu Controller's View ,
I want to call Etiketler table and its Id.
I already use Konu Model But i want to use Etiketler Model in 1 View.
How can i call 2 tables(models)in 1 view page ?

You will need to create a ViewModel:
public class KonuEtiketlerViewModel
{
public virtual List<Konu> Konus {get; set;}
public virtual List<Etiketler> Etiketlers {get; set;}
}
and in your controller:
public ActionResult Index()
{
SonerSevincComEntities context = new SonerSevincComEntities();
var viewModel = new KonuEtiketlerViewModel
{
Konus = context.Konu.ToList(),
Etiketlers = context.Etiketler.ToList()
}
return View(viewModel);
}
View:
#model projectname.ViewModels.KonuEtiketlerViewModel // you must create a new class, preferably inside a ViewModels folder, called KonuEtiketlerViewModel
//you can access all your properties here....

Related

Xamarin - How to pass variable to viewmodel

I have 2 Views. One has an event, that passes two variables to the second page and loads the page up:
private void CollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var item = (GalleryListEntry)e.CurrentSelection.FirstOrDefault();
Navigation.PushModalAsync(new Gallery(item.PhotographerCode, item.GalleryCode));
}
in the second page I have this:
public Gallery(string photographerCode, string galleryCode)
{
InitializeComponent();
}
The second page, has a Collection view that has its own Bindingsource.
For this bindingsource i have a Model, a Service, and a ViewModel. The service is called by the Viewmodel, and returns a List of images to be shown in the second page's collection view.
Inside this service class, I would need to access to the two variables passed above (photograperCodeand galleryCode) but I cannot figure out how to pass the variables to the ViewModel so i can then forward it to the class.
ViewModel:
using GalShare.Model;
using GalShare.Service;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
namespace GalShare.ViewModel
{
class GalleryViewModel
{
public ObservableCollection<Gallery> Galleries { get; set; }
public GalleryViewModel()
{
Galleries = new GalleryService().GetImageList();
}
}
}
I tried like this
((GalleryViewModel)this.BindingContext).pCode = photographerCode;
((GalleryViewModel)this.BindingContext).gCode = galleryCode;
but I get this error: System.NullReferenceException: 'Object reference not set to an instance of an object.'
BindingContext is Null, but in the Xaml file i have this:
<ContentPage.BindingContext>
<vm:GalleryViewModel/>
</ContentPage.BindingContext>
This should work fine. First in your Gallery
public Gallery(string photographerCode, string galleryCode)
{
InitializeComponent();
BindingContext = new GalleryViewModel(photographerCode, galleryCode);
}
And now in the ViewModel
class GalleryViewModel
{
public ObservableCollection<Gallery> Galleries { get; set; }
public GalleryViewModel(string pCode, string gCode)
{
this.pCode = pCode;
this.gCode = gCode;
Galleries = new GalleryService().GetImageList();
}
}

Can map model to viewModel, but viewModel to model won't work

I use Automapper to map my domain model to my viewModel and this works great. Atm I'm just prototyping and changing the Model a lot, so at this point my viewModel is almost an exact copy of my Model and my viewModel references classes from the domain for its complex types (so I only have to keep the root class of my viewModel in sync with my domain model).
Although mapping from the domain model to the viewModel works great, mapping the viewModel back to the domain model doesn't work very well. The values directly in the viewModel do map, but the lists of a complex type don't. How do i fix this?
This is a simple representation of my models:
public class model
{
public int someValue { get; set; }
public virtual ICollection<ComplexType> aList { get; set; }
}
public class viewModel
{
public int someValue { get; set; }
public virtual ICollection<ComplexType> aList { get; set; }
}
public class ComplexType
{
public int someOtherValue { get; set; }
}
In this case they both model and viewModel reference the same file for ComplexType so these can't differ.
Did you use ReverseMap when mapping from ViewModel to Domain Model?
public class CustomProfile : Profile
{
protected override void Configure()
{
// Mapper.CreateMap<Model, ViewModel>();
// Mapper.CreateMap<ViewModel, Model>();
Mapper.CreateMap<Model, ViewModel>().ReverseMap();
}
}
This works perfectly fine and maps everything with no issue.
[TestInitialize]
public void Initialize()
{
Mapper.Initialize(conf => conf.AddProfile(new CustomProfile()));
}
[TestMethod]
public void AssertConfiguration()
{
Mapper.AssertConfigurationIsValid();
}
[TestMethod]
public void Test()
{
var model = new Model()
{
ComplexTypes = new Collection<ComplexType>() { new ComplexType() { SomeOtherValue = 1 }, new ComplexType() { SomeOtherValue = 4 } },
SomeValue = 3
};
var viewModel = Mapper.Map<ViewModel>(model);
Assert.AreEqual(model.SomeValue, viewModel.SomeValue);
Assert.AreEqual(model.ComplexTypes.Count, viewModel.ComplexTypes.Count);
Assert.AreEqual(model.ComplexTypes.ElementAt(0), viewModel.ComplexTypes.ElementAt(0));
Assert.AreEqual(model.ComplexTypes.ElementAt(1), viewModel.ComplexTypes.ElementAt(1));
model = Mapper.Map<Model>(viewModel);
Assert.AreEqual(viewModel.SomeValue, model.SomeValue);
Assert.AreEqual(viewModel.ComplexTypes.Count, model.ComplexTypes.Count);
Assert.AreEqual(viewModel.ComplexTypes.ElementAt(0), model.ComplexTypes.ElementAt(0));
Assert.AreEqual(viewModel.ComplexTypes.ElementAt(1), model.ComplexTypes.ElementAt(1));
}

EntityFramework 5 Code First - lookup table gets duplicate records

I am trying the EF5 CodeFirst and cannot get the simple setup to work ;(
I have two classes Foo and Bar where Bar represent lookup table.
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Bar Bar { get; set; }
}
public class Bar
{
public int Id { get; set; }
public string Description { get; set; }
}
public class MyDbContext : DbContext
{
static MyDbContext()
{
Database.SetInitializer<MyDbContext>(null);
}
public MyDbContext(): base("testEF"){}
public DbSet<Foo> Foos { get; set; }
public DbSet<Bar> Bars { get; set; }
}
Now I have created a static class that serves as DataAccess Layer - in real-world application it will be on different physical tier
public static class DataAccess
{
public static Bar GetBarById(int id)
{
using (var db = new MyDbContext())
{
return db.Bars.SingleOrDefault(b => b.Id == id);
}
}
public static Foo InsertFoo(Foo foo)
{
using (var db = new MyDbContext())
{
db.Foos.Add(foo);
db.SaveChanges();
}
return foo;
}
}
I am initializing the DB with seed method:
internal sealed class Configuration : DbMigrationsConfiguration<testEF.MyDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(testEF.MyDbContext context)
{
context.Bars.AddOrUpdate(
new Bar { Description = "Bar_1" },
new Bar { Description = "Bar_2" }
);
}
}
This creates two records in Bars table. So far so good...
Here is my Main function
static void Main(string[] args)
{
var bar1 = DataAccess.GetBarById(1);
var foo = new Foo
{
Name = "Foo_1",
Bar = bar1
};
DataAccess.InsertFoo(foo);
}
After the app runes there is a record in the Foos table:
Id Name Bar_Id
1 Foo_1 3
Why Bar_Id is 3? The EF actually inserted new record to Bars table!
Id Description
1 Bar_1
2 Bar_2
3 Bar_1
What I am doing wrong?
UPDATE:
I have found a workaround - to attach Bar property prior to inserting the record:
public static Foo InsertFoo(Foo foo)
{
using (var db = new MyDbContext())
{
db.Bars.Attach(foo.Bar);
db.Foos.Add(foo);
db.SaveChanges();
}
return foo;
}
It is working now but this is more like a hack than a valid solution...
In real-world application the complexity of the objects could become a huge problem.
I am open to better solutions
The problem is that bar1 comes from a different data context. Your InsertFoo method implicitly adds it to the second context by building a relationship with the Foo. You want these two to share a context. So use a single context for the whole scope of the Main method.
The complexity you mention (which I agree with you) is caused by using a static class for your data access component. It forces you to separate your DBContext's across method calls. Instead of doing it that way, why not create a normal class, and build the context in the constructor.
With this, you don't need to attach foo.Bar anymore.
public class DataAccess
{
private MyDbContext _context;
public DataAccess(){
_context = new MyDbContext();
}
public Bar GetBarById(int id)
{
return _context.Bars.SingleOrDefault(b => b.Id == id);
}
public Foo InsertFoo(Foo foo)
{
_context.Foos.Add(foo);
_context.SaveChanges();
return foo;
}
}
There are many ways you can build on and enhance this. You could create an interface for MyDbContext called IDbContext and using a DI framework inject it into this class. Similarly, you could do the same for the DataAccess class and inject that into wherever it's needed.

Pass more than one model to view

public ActionResult Index()
{
var pr = db.products;
return View(pr);
}
Firstly - I want to pass to the view more data - something like:
public ActionResult Index()
{
var pr = db.products;
var lr = db.linksforproducts(2)
return View(pr,lr);
}
How do I read the lr data in the view?
Secondly - on the view I have a table of products, and I want to add to the table a column with all the tags of this products. How do I get the tags for every product?
now i create this code
public class catnewModel
{
public IQueryable<category> dl { get; set; }
public IQueryable<product> dr { get; set; }
}
and my controller
public ActionResult Index()
{
var pr = db.products;
var pl = db.categories;
catnewModel model = new catnewModel();
model.dr = pr;
model.dl = pl;
return View(model);
}
in my view i try to iterate over
<% foreach (var item in Model.dr) %>
but i get error on
error CS1061: 'System.Collections.Generic.IEnumerable<amief.Models.catnewModel>' does not contain a definition for 'dr' and no extension method
I have done this by making a ViewModel specific to the view you need the information in.
Then within that ViewModel just have properties to house your other models.
Something like this:
public class ViewModel
{
public List<ProductModel> Products(){get; set;}
public List<LinksForProductModel> LinksForProducts(){get; set;}
}
public ActionResult Index()
{
var pr = db.products;
var lr = db.linksforproducts(2)
ViewModel model = new ViewModel();
model.Products = pr;
model.LinksForProducts = lr;
return View(model);
}
Create a view model containing two properties:
public class MyViewModel
{
public IEnumerable<Product> Products { get; set; }
public IEnumerable<LinkProduct> Links { get; set; }
}
And in your controller:
public ActionResult Index()
{
var model = new MyViewModel
{
Products = db.products,
Links = db.linksforproducts(2)
};
return View(model);
}
Usually - You create view model per view.
In Your case, that would be:
public class IndexModel{
public ProductModel[] Products{get;set;}
public LinkForProduct[] Links{get;set;}
}
public ActionResult Index(){
var model=new IndexModel{
Products=Map(db.products),
Links=Map(db.linksforproducts(2)};
return View(model);
}

Display results of two queries in view using asp.net MVC2

I have this code that works.
public class HelloWorldController : Controller
{
UAStagingEntities db = new UAStagingEntities();
public ActionResult Index(int? id)
{
var depot = db.CSLA_DEPOT.Where(c => c.DEPOT_ID == id.Value);
return View(depot.ToList());
}
}
What I don't know how to do is display a view with results from two queries. How would I create the view to show both depot and address? and how would I code the return statement?
public class HelloWorldController : Controller
{
UAStagingEntities db = new UAStagingEntities();
public ActionResult Index(int? id)
{
var depot = db.CSLA_DEPOT.Where(c => c.DEPOT_ID == id.Value);
var Address = db.CSLA_ADDRESS.Where(a => a.CSLA_DEPOT.DEPOT_ID == id.Value);
return View(depot.ToList());
}
}
EDIT *
I added this model
namespace CustomerCareMVC.Models
{
public class CSLA_StagingModel
{
public List<CSLA_DEPOT> depots { get; set; }
public List<CSLA_ADDRESS> addresses { get; set; }
}
}
And added this method in the controller
public ActionResult ShowAllTables()
{
var model = new CSLA_StagingModel()
{
depots = db.CSLA_DEPOT.Where(c => c.DEPOT_ID == 10065),
addresses = db.CSLA_ADDRESS.Where(a => a.CSLA_DEPOT.DEPOT_ID == 10065),
};
return View(model);
}
I get squiggly line under these two lines
depots = db.CSLA_DEPOT.Where(c => c.DEPOT_ID == 10065),
addresses = db.CSLA_ADDRESS.Where(a => a.CSLA_DEPOT.DEPOT_ID == 10065),
with this error message
Error 1 Cannot implicitly convert type 'System.Linq.IQueryable' to 'System.Collections.Generic.List'. An explicit conversion exists (are you missing a cast?) C:\CustCareMVC\CustomerCareMVC\CustomerCareMVC\Controllers\HelloWorldController.cs 59 26 CustomerCareMVC
You would need to create a ViewModel that has the following paramters:
public IQueryable<CSLA_DEPOT> depots {get; set;}
public IQueryable<CSLA_ADDRESS> addresses {get; set;}
You would then need to create an instance of this new View Model in your controller like so:
var model = new ViewModelName(){
depots = db.CSLA_DEPOT.Where(c => c.DEPOT_ID == id.Value),
addresses = db.CSLA_ADDRESS.Where(a => a.CSLA_DEPOT.DEPOT_ID == id.Value),
};
You would then need to pass this model to your view like so:
return View(model);
In your view you would access the two different collections like so:
Model.depots
Model.addresses
Hope this helps, leave me a comment if you have any questions.
Create a special object that contains two items of the types returned by your queries. Then you can access them with Model.depot and Model.Address in your View.