One to many, one view do I need a custom model? - asp.net-mvc-3

I have a database base first application so I have no homemade modals as such, just the ones created automatically. I want to display in a single view the one and many parts from a select in single row in an html table/list, here is the SQL that works great in a re-created MS Access Query, - some brackets:
SELECT Facilitiy.FacilityName, Facilitiy.FacilityImage, FacilityDetail.FacilityDetailDescription
FROM FacilityDetail INNER JOIN Facilitiy ON FacilityDetail.FacilityDetailID = Facilitiy.FacilityFK
WHERE FacilityFK = id
And the LINQ that gives me the correct many part of the list:
from fd in db.FacilityDetails
join f in db.Facilities on fd.FacilityID equals f.FacilityFK
where f.B FacilityFK == id
select f
I had kind of hoped that would do it as the SQL does but I need to create a modal that I can put in a view to display:
FacilityImage(one side) | FacilityName(one side) | FacilityDetailDescription(many side)
I have heard I can simply do it by doing something like this???
from fd in db.FacilityDetails.Include("Facilities")
but it seems to make no difference!
Which leads me to believe I need to create a new custom model? If so how would i write it?
I tried something like this but I cant get it to work.
public class FacilitiyDetails
{
public string FacilitiesDescription { get; set; }
public string FacilitiesImage { get; set; }
public string BeachFacilitiesDescription { get; set; }
{
I'm not quite sure what i'm supposed to do here!

Yes you will need a custom model because you're wanting to display multiple types. You'll need to have something like:
public class FacilityModel
{
public Facility Facility { get; set; }
public List<FacilityDetails> FacilityDetails { get; set; }
}
Based on your class above and assuming you have a Facility class already. Then you'll need to change your LINQ to first get the Facility details:
var facility = (from f in db.Facilities
where f.FacilityID == id
select f)
.FirstOrDefault(); //just being safe here,
//if it's null, you'll want to escape out of
//the code below
Then you'll need to get all equivalent FacilityDetails for that facility by doing:
var facilityDetails = (from fd in db.FacilityDetails
where fd.FacilityFK == id
select fd).ToList()
Then you can create a new instance of your Model by doing:
var model = new FacilityModel
{
Facility = facility,
FacilityDetails = facilityDetails
};

Related

Combining Linq Expressions for Dto Selector

We have a lot of Dto classes in our project and on various occasions SELECT them using Expressions from the entity framework context. This has the benefit, that EF can parse our request, and build a nice SQL statement out of it.
Unfortunatly, this has led to very big Expressions, because we have no way of combining them.
So if you have a class DtoA with 3 properties, and one of them is of class DtoB with 5 properties, and again one of those is of class DtoC with 10 properties, you would have to write one big selector.
public static Expression<Func<ClassA, DtoA>> ToDto =
from => new DtoA
{
Id = from.Id,
Name = from.Name,
Size = from.Size,
MyB = new DtoB
{
Id = from.MyB.Id,
...
MyCList = from.MyCList.Select(myC => new DtoC
{
Id = myC.Id,
...
}
}
};
Also, they cannot be reused. When you have DtoD, which also has a propertiy of class DtoB, you would have to paste in the desired code of DtoB and DtoC again.
public static Expression<Func<ClassD, DtoD>> ToDto =
from => new DtoD
{
Id = from.Id,
Length = from.Length,
MyB = new DtoB
{
Id = from.MyB.Id,
...
MyCList = from.MyCList.Select(myC => new DtoC
{
Id = myC.Id,
...
}
}
};
So this will escalate pretty fast. Please note that the mentioned code is just an example, but you get the idea.
I would like to define an expression for each class and then combine them as required, as well as EF still be able to parse it and generate the SQL statement so to not lose the performance improvement.
How can i achieve this?
Have you thought about using Automapper ? You can define your Dtos and create a mapping between the original entity and the Dto and/or vice versa, and using the projection, you don't need any select statements as Automapper will do it for you automatically and it will project only the dto's properties into SQL query.
for example, if you have a Person table with the following structure:
public class Person
{
public int Id { get; set; }
public string Title { get; set; }
public string FamilyName { get; set; }
public string GivenName { get; set; }
public string Initial { get; set; }
public string PreferredName { get; set; }
public string FormerTitle { get; set; }
public string FormerFamilyName { get; set; }
public string FormerGivenName { get; set; }
}
and your dto was like this :
public class PersonDto
{
public int Id { get; set; }
public string Title { get; set; }
public string FamilyName { get; set; }
public string GivenName { get; set; }
}
You can create a mapping between Person and PersonDto like this
Mapper.CreateMap<Person, PersonDto>()
and when you query the database using Entity Framework (for example), you can use something like this to get PersonDto columns only:
ctx.People.Where(p=> p.FamilyName.Contains("John"))
.Project()
.To<PersonDto>()
.ToList();
which will return a list of PersonDtos that has a family name contains "John", and if you run a sql profiler for example you will see that only the PersonDto columns were selected.
Automapper also supports hierachy, if your Person for example has an Address linked to it that you want to return AddressDto for it.
I think it worth to have a look and check it, it cleans a lot of the mess that manual mapping requires.
I thought about it a little, and I didn't come up with any "awesome" solution.
Essentially you have two general choices here,
Use placeholder and rewrite expression tree entirely.
Something like this,
public static Expression<Func<ClassA, DtoA>> DtoExpression{
get{
Expression<Func<ClassA, DtoA>> dtoExpression = classA => new DtoA(){
BDto = Magic.Swap(ClassB.DtoExpression),
};
// todo; here you have access to dtoExpression,
// you need to use expression transformers
// in order to find & replace the Magic.Swap(..) call with the
// actual Expression code(NewExpression),
// Rewriting the expression tree is no easy task,
// but EF will be able to understand it this way.
// the code will be quite tricky, but can be solved
// within ~50-100 lines of code, I expect.
// For that, see ExpressionVisitor.
// As ExpressionVisitor detects the usage of Magic.Swap,
// it has to check the actual expression(ClassB.DtoExpression),
// and rebuild it as MemberInitExpression & NewExpression,
// and the bindings have to be mapped to correct places.
return Magic.Rebuild(dtoExpression);
}
The other way is to start using only Expression class(ditching the LINQ). This way you can write the queries from zero, and reusability will be nice, however, things get harder & you lose type safety. Microsoft has nice reference about dynamic expressions. If you structure everything that way, you can reuse a lot of the functionality. Eg, you define NewExpression and then you can later reuse it, if needed.
The third way is to basically use lambda syntax: .Where, .Select etc.. This gives you definitely better "reusability" rate. It doesn't solve your problem 100%, but it can help you to compose queries a bit better. For example: from.MyCList.Select(dtoCSelector)

Linq selecting from muliple tables

I have the following model
public class SummaryModel
{
public int CompanyCount { get; set; }
public int GroupCount { get; set; }
public int ProjectCount { get; set; }
public int ResourcesCount { get; set; }
public int PeopleCount { get; set; }
}
I would like to use linq to query my database and return record counts from multiple tables and populate this model object.
This is how I am doing it:
using (var ctx = new WeWorkModel.weWorkEntities())
{
var summary = new SummaryModel()
{
CompanyCount = ctx.Companies.Count(),
PeopleCount = ctx.People.Count(),
GroupCount = ctx.Groups.Count(),
ProjectCount = ctx.Projects.Count(),
ResourcesCount = ctx.Resources.Count()
};
}
Is this the most efficient way to do this?
Yes, this is the most efficient way - equivalent to writing sql query as this does not fetch the objects but only does a count on the server. So something like this ( using profiler I tracked the query)
SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM [dbo].[Company] AS [Extent1]
) AS [GroupBy1]
Do you need to store this model in a database or change it's values after instantiating? If no, why not put this code block inside of a parameterless constructor and mark the fields readonly as to avoid using this model differently than intended. If you find later you need greater control over initialization of fields, simply add another constructor to deal with that specific case. To the main question, I see nothing particularly inefficient with your way of handling it. Although, with code there is nearly always terser ways or more efficient ways of handling just about any scenario.

Coalesce fields in a .net MVC 4 model without getting "Only initializers, entity members, and entity navigation properties are supported" from LINQ

The answer to this question gave rise to this other question: How to use LINQ expressions as static members of classes in queries when the class is related multiple times to a second class
I have an existing ASP.net MVC 4 site which I need to modify.
The core entity within this site are Items that are for sale, which are created by several different companies and divided into several categories. My task is to allow each company its own optional alias for the global categories. Getting the two categories set up in the database and model was no problem, making the application use the new optional alias when it exists and default to the global otherwise is where I'm struggling to find the optimal approach.
Adding a coalesce statement to every LINQ query will clearly work, but there are several dozen locations where this logic would need to exist and it would be preferable to keep this logic in one place for when the inevitable changes come.
The following code is my attempt to store the coalesce in the model, but this causes the "Only initializers, entity members, and entity navigation properties are supported." error to be thrown when the LINQ query is executed. I'm unsure how I could achieve something similar with a different method that is more LINQ friendly.
Model:
public class Item
{
[StringLength(10)]
[Key]
public String ItemId { get; set; }
public String CompanyId { get; set; }
public Int32 CategoryId { get; set; }
[ForeignKey("CategoryId")]
public virtual GlobalCategory GlobalCategory { get; set; }
[ForeignKey("CompanyId, CategoryId")]
public virtual CompanyCategory CompanyCategory { get; set; }
public String PreferredCategoryName
{
get{
return (CompanyCategory.CategoryAlias == null || CompanyCategory.CategoryAlias == "") ? GlobalCategory.CategoryName : CompanyCategory.CategoryAlias;
}
}
}
Controller LINQ examples:
var categories = (from i in db.Items
where i.CompanyId == siteCompanyId
orderby i.PreferredCategoryName
select i.PreferredCategoryName).Distinct();
var itemsInCategory = (from i in db.Items
where i.CompanyId == siteCompanyId
&& i.PreferredCategoryName == categoryName
select i);
For one you are using a compiled function (getPreferredCategoryName) in the query, unless EF knows how to translate that you are in trouble.
Try the following in item definition:
public static Expression<Func<Item,String>> PreferredCategoryName
{
get
{
return i => (i.CompanyCategory.CategoryAlias == null || i.CompanyCategory.CategoryAlias == "") ?
i.GlobalCategory.CategoryName :
i.CompanyCategory.CategoryAlias;
}
}
Which is used as follows:
var categories = db.Items.Where(i => i.CompanyID == siteCompanyId)
.OrderBy(Item.PreferredCategoryName)
.Select(Item.PreferredCategoryName)
.Distinct();
This should work as you have a generically available uncompiled expression tree that EF can then parse.

ASP.NET MVC 3 multiple Models to single Form using DB

I have a question.
My question actually extends from this one:
Shortly - what I want to get: 3 models, and 1 super model for this specific view. This super model fills(properly) IENumerable, IENumerable, IENumerable, to use them in View part. (as far as I understand it, at least...)
In this other topic Dan Revell proposed verry nice and elegant solution, but this solution does not fetch data from DB itself...
Question:
What must be done to get data in this model from DB, not from "new" instance constructors?
While using this approach tried to fetch data from DBContext. And got some problems in it ) I can't understand when (or how) to create my DBContext... Or how to access one that is created by application...
Tried to create it forcefully in Controller, like
using (var Db = new thetaskermvc.Models.TaskerDBContext())
{
var themodel = new thetaskermvc.Models.TotalView();
//Jobbers
themodel.Jobberz = new Dictionary<int, thetaskermvc.Models.Jobbers>();
var jobbers = from Jobbers in Db.Jobbers.OrderBy(g => g.jobb_name) select Jobbers;
foreach (Models.Jobbers ad in jobbers)
{
themodel.Jobberz.Add(ad.jobb_id,
new Models.Jobbers(ad.jobb_id, ad.jobb_name, ad.jobb_from, ad.jobb_carma, ad.jobb_status, ad.jobb_balance, ad.jobb_time));
}
if (themodel.Jobberz.Count == 0)
{
themodel.Jobberz.Add(-1, new Models.Jobbers(0, "NOTHING FOUND",DateTime.Now,0,"",0,0));
}
}
But as created that way Context stops it's existence (?) after passing data away from controller - I can't use it any other way but to get all data inside this controller, and fill data in model by direct add into collections in it (while use of IENumerable would fetch data on-demand, as far as I get it).
So.. If it ain't hard please enlighten me about - is it Ok to use such approach, or there is some other "common" way? Becaus beside it's clumsiness - this approach works...
PS I'm quite new to Asp, yet...
I have one view model per view with data from multiple tables (if required). On my view I have data that needs to be loaded from 2 different database tables. In my grant application controller I have the following:
private readonly IBankService bankService;
private readonly IAccountTypeService accountTypeService;
public GrantApplicationController(IBankService bankService, IAccountTypeService accountTypeService)
{
// Check incoming parameters for null values
this.bankService = bankService;
this.accountTypeService = accountTypeService;
}
In my Create action method I populate my banks and account types (to be used in drop downs) like this (different tables):
public ActionResult Create()
{
GrantApplicationCreateViewModel viewModel = new GrantApplicationCreateViewModel
{
Banks = bankService.FindAll(),
AccountTypes = accountTypeService.FindAll()
}
// Do what ever else you need to get done
return View(viewModel);
}
My partial view model would like this:
public class GrantApplicationCreateViewModel
{
public int BankId { get; set; }
public IEnumerable<Bank> Banks { get; set; }
public int AccountTypeId { get; set; }
public IEnumerable<AccountType> AccountTypes { get; set; }
// Other properties
}
In my repository class I would use the database context like this (I use Entity Framework code first):
public class BankRepository : IBankRepository
{
HefContext db = new HefContext
public IEnumerable<Bank> FindAll()
{
return db.Banks.OrderBy(x => x.Name);
}
}
In my database context class:
public class HefContext : DbContext
{
public DbSet<Bank> Banks { get; set; }
public DbSet<AccountType> AccountTypes { get; set; }
}
Doing it this way you can have one view model that has data from multiple sources. I hope this answers your question? If you need more explanation please let me know :)
You may want to have a look at this post, it explains (with a sample project) how an ideal MVC application architecture should be.
In your code sample above, your shouldn't have any references to DbContexts in a controller. Controller's job is to control the flow of requests not to connect to the DB and perform Model population.

MVC View Model Organization

I'm new to MVC and I'm trying to understand how to organize my ModelViews. The first problem is Drop Down data. I have an Equipment Model and an EquipmentViewModel that looks like this:
public class EquipmentViewModel
{
public Equipment Equipment { get; private set; }
public SelectList EquipmentCategories { get; private set; }
private MyEntities db = new MyEntities();
public EquipmentViewModel(Equipment equipment)
{
Equipment = equipment;
EquipmentCategories = new SelectList(db.EquipmentCategories.Where(c => c.IsActive),
"EquipmentCategoryID", "Description");
}
Please note the SelectList for my category dropdown. This is all well and good. However I have another Model called Inventory. Inventory has an EquipmentID property (corresponding to a piece of equipment you see). For the creation of an inventory item it would be useful to have a drop down for the equipment category. I already have this select list in my EquipmentViewModel and it feels wrong some how to duplicate that code for the InventoryViewModel.
I have considered something like this:
public class InventoryViewModel
{
MyEntities db = new MyEntities();
public Inventory Inventory { get; set; }
public EquipmentViewModel EquipmentViewModel { get; set; }
}
This seems okay to me except I am going to have an Index page for the InventoryViewModel. Basically I would be returning a List of InventoryViewModels which each has an EquipmentViewModel where in each of those has the exact same list of categories. This, too, feels wrong and I think I am misunderstanding some crucial piece of the MVC puzzle.
It also leads me to my second question: How would I return such a monstrosity from the controller? I imagine it looking something like this:
var list = db.Inventories
.Select(i => new InventoryViewModel
{
Inventory = i,
EquipmentViewModel = new EquipmentViewModel(i.EquipmentID)
});
Which means that I'd basically be making separate trips to the database (inside the EquipmentViewModel constructor) for each EquipmentID rather than being able to join on the id. For example if I just needed the description I could do this:
var list = from i in db.Inventories
join e in db.Equipments
on i.EquipmentID equals e.EquipmentID
select new InventoryViewModel
{
Inventory = i,
EquipmentName = e.Description
};
Which I believe would have much better performance. I greatly appreciate any wisdom that anyone could offer. Thanks!
I have and idea for you,
there is no point of ducplicating your views if they are doing same thing. however if they are not doing exactly the same is better to exted or create new view than have one big one that is shared for all parts.
You can have model such as this
public class InventoryViewModel{
// contains all categories for every inventory
public SelectListItem EquipmentSelect {get;set;}
//this will contain all the items you want to assign
public List<Inventories> ListOfInventories{get;set;}
}
after in view you can create partial view for every item with the select list item in to it

Resources