I am working on asp.net MVC 3 project. I am using EF 4.1 code first approach. I have entity class called disputes. It maps to a table in database name tblDisptes. It has three properties names Lastviewedby, Lastupdatedby, LastRespondedBy ... all three integers. I have created a viewmodel 'disputeviewmodel' with three more properties Lastviewedbyname, Lastupdatedbyname, LastRespondedByname and a property named dispute. Now my repository function returns list of disputes. how to convert this list to List of disputeviewmodel so that these three properties are filled with the names ?
Please suggest.
Your view model doesn't really need a property named dispute. A view model should not reference your domain models.
As far as the mapping is concerned one possibility is to manually do it but that could quickly become cumbersome with more complex models:
public ActionResult Foo()
{
IEnumerable<disputes> disputes = ... fetch from repo
IEnumerable<disputeviewmodel> disputeViewModels = disputes.Select(x => new disputeviewmodel
{
Lastviewedbyname = x.Lastviewedby,
Lastupdatedbyname = x.Lastupdatedby,
LastRespondedByname = x.LastRespondedBy
});
return View(disputeViewModels);
}
So a better approach would be to use AutoMapper:
public ActionResult Foo()
{
IEnumerable<disputes> disputes = ... fetch from repo
IEnumerable<disputeviewmodel> disputeViewModels = Mapper.Map<IEnumerable<disputes>, IEnumerable<disputeviewmodel>>(disputes);
return View(disputeViewModels);
}
Why your Dispute doesn't look like that?
class Dispute
{
public User LastViewedBy;
public User Lastupdatedbyname
public User LastRespondedByname
}
That's how it should look. Then problem solved. When you query for Disputes you already have Users (with there usernames) ready.
Related
In my edmx model are 2 related tables: Challenge and ChallengeNote (has FK back to ChallengeID)
I can do this in breeze all day long
var qry = dataservice.getQuery("Challenges");
However, this fails every time:
var qry = dataservice.getQuery("Challenges").expand("ChallengeNotes");
The searchFailed is called and is the only error information in the console.
return dataservice.execute(qry.inlineCount(true))
.then(seachSucceeded)
.fail(searchFailed);
Does Breeze support relational data like this?
Does one need to write some custom code to support?
What am I missing?
Here's related answered question, but I was already following (unless I missed something) the answer's solution (and why I have the 2 context.Configuration settings in my ContextProvider).
breezejs-error-when-loading-an-entity-with-related-data
Here's another similar question that's been unanswered breeze-expand-query-fails-with-object-object-has-no-method-getproperty
Here's my provider code (want to use the BeforeSaveEntity override further on in the project):
public class ModelProvider : EFContextProvider<ModelEntities>
{
public ModelProvider()
: base()
{
this.Context.Configuration.LazyLoadingEnabled = false;
this.Context.Configuration.ProxyCreationEnabled = false;
}
}
Here's my controller code:
[BreezeController]
public class DataController : ApiController
{
readonly ModelProvider _contextProvider = new ModelProvider();
[HttpGet]
public string Metadata()
{
return _contextProvider.Metadata();
}
[Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
[HttpGet]
public IQueryable<Challenge> Challenges()
{
return _contextProvider.Context.Challenges.Include(x => x.ChallengeNotes);
}
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle)
{
return _contextProvider.SaveChanges(saveBundle);
}
[HttpGet]
public IQueryable<ChallengeNote> ChallengeNotes()
{
return _contextProvider.Context.ChallengeNotes;
}
}
When I browse to the URL, it's including the related entity:
http://localhost:53644/breeze/data/Challenges?$filter=Active%20eq%20true&$top=10&$expand=ChallengeNotes&$inlinecount=allpages
Here is the data coming from the Controller
At this point all things, imo, are pointing to Breeze configuration on either the Server or Client.
TIA
Breeze absolutely does support this, but you do need to make sure that your Entity Framework model is set up correctly. Take a look at the DocCode sample in the Breeze zip for a number of examples of using both expand (client side) or EF include (server side) clauses.
One guess about your problem is that you are using the Breeze camelCasing naming convention and therefore your "expand" clause should be
var qry = dataservice.getQuery("Challenges").expand("challengeNotes");
i.e. "challengeNotes" (note the casing) is the name of the client side property that corresponds to a server side property of "ChallengeNotes". To clarify, "expand" clauses take the names of client side "properties" as parameters and property names are what are transformed as a result of the Breeze.NamingConvention.
In contrast, a query resource name i.e. "Challenges" in your example is the name of the server side resource ( as a result of marking your "Challenges" method with the [HttpGet] annotation. This name is NOT affected by the NamingConvention.
Side notes: Your example has both an expand and an Include clause. Either of these is sufficient all by itself. You do not need both. In general you can either include an "expand" clause in your client side query OR have an Entity Framework "Include" clause on the server. The advantage of the first is that you can control the expand on the client, the advantage of the second is that you can insure that every query for a specified resource always fetches some related entities.
Hope this helps!
So I have three roles, administrators, companies and employees in my mvc .net application that uses asp.net membership in a separate database. I moved the .net membership in a different database for now because everytime I modify the model, the .net membership tables are getting deleted.
Anyway, I am handling different roles using if/else in the action method. For example, in Index() action, I check if the user is in administrators role, then create model and linq query based on that. If user in companies role, different query and if user in employees role, different query. check code below. The model created after the if condition is passed to the View.
I feel like this is not the best way to handle roles. Is this the best way to handle roles? I am considering different areas as well, but I use same views for the different roles, i think it may not be productive.
Any suggestion/idea greatly appreciated.
[Authorize]
public class CompanyController : Controller
{
private MyDBContext db = new MyDBContext();
//
// GET: /Company/
public ViewResult Index()
{
var viewModel = new CompanyIndexViewModel();
if (Roles.IsUserInRole("administrators")) {
viewModel = new CompanyIndexViewModel { Companies = db.Companies.ToList() };
}
else if (Roles.IsUserInRole("companies")) {
viewModel = new CompanyIndexViewModel { Companies = db.Companies.Where(c => c.Username.ToLower().Equals(this.User.Identity.Name.ToLower())).ToList() };
}
else if (Roles.IsUserInRole("employees")) {
string userName = this.User.Identity.Name.ToLower();
var companies = db.Companies.Where(c => c.Appointments.Any(a =>
a.Employee.Username.ToLower() == userName)).ToList();
viewModel = new CompanyIndexViewModel { Companies = companies.ToList() };
}
return View(viewModel);
}
....
There is two things I would do:
Firstly, what StanK said and move it out of the controller action. However, I would move it out of the Controller all together. This sort of logic shouldn't really reside in the Controller to begin with (whether it be in an action, or a private method in the controller).
Think about it this way: What if your logic for who gets to see what companies changes.. you'll have to change it in all sorts of different places.
Secondly, I would create a constructor for the CompanyIndexViewModel that took in a list of Company instead of initializing it inline like that. Does the CompanyIndexViewModel contain anything else besides companies?
// your controller
public ViewResult Index()
{
var viewModel = CompanyIndexViewModel(CompanyService.GetCompaniesForCurrentUser());
return View(viewModel);
}
Ideally, you would also have your controller depend on an interface representing the "CompanyService", and have that injected into your controller.
Take a look at this blog which outlines using Ninject with MVC 3. It's ridiculously simple to setup for something that is so powerful for you later on.
If you take one thing away from what I've said above, it's probably best to start with moving your logic out of the controller.
I would move the code that builds the list of Companies to it's own method to tidy up the controller action , which would also make the logic that determines the list of Companies for the current user re-useable.
e.g.
private List<Company> GetCompaniesForCurrentUser()
{
var userName = this.User.Identity.Name.ToLower();
if (Roles.IsUserInRole("administrators"))
return db.Companies.ToList();
if (Roles.IsUserInRole("companies"))
return db.Companies.Where(c => c.Username.ToLower().Equals(userName)).ToList();
if (Roles.IsUserInRole("employees"))
return db.Companies.Where(c => c.Appointments.Any(a =>
a.Employee.Username.ToLower() == userName)).ToList();
throw new AuthorizationException("User " + userName + " is not authorised.");
}
public ViewResult Index()
{
var viewModel = new CompanyIndexViewModel { Companies = GetCompaniesForCurrentUser() };
return View(viewModel);
}
I'm using MVC3 with EF (version 4, but not sure if 4.0,4.1,etc). I've been fighting with this since yesterday and I don't find the answer anywhere. I'm using the book "Pro Entity Framework 4.0".
I did Model First approach and because I want to use inheritance I created a basic model to do the first testings (sorry, click the link, I don't have enough rep to put a picture):
EF Model
Then with this model I created the database. I'm not very happy with the naming convention, because in spite of pluralizing the entity names, for the derived class table it created a prefixed-single table name. I'm sorry I don't have SSMS installed but have a look through the Server Explorer, see the picture:
DB created from EF Model
Then I created controllers for BaseClass with the template "Controller with read/write actions and views, using Entity Framework". It works great! It created all the views, CRUD.
For instance in the Details view I have this code:
//
// GET: /BaseClass/Details/5
public ViewResult Details(int id)
{
BaseClass baseclass = db.BaseClasses.Single(b => b.Id == id);
return View(baseclass);
}
It works fine.
Then I did the same for the DerivedClass and I got the controller with all the CRUD actions and the views. And now the problem. For instance the Details controller of the DerivedClass is like this:
//
// GET: /DerivedClass/Details/5
public ViewResult Details(int id)
{
DerivedClass derivedclass = db.BaseClasses.Single(d => d.Id == id);
return View(derivedclass);
}
As you can see it tries to get db.BaseClasses instead of db.DerivedClasses, with gives a compilation error, but db does not provide any access to the DerivedClass entity, there is nothing in db at all related with DerivedClass.But if I create manually an instance of DerivedClass in the code it is possible:
MyNamespace.Blablabla.Site.Models.DerivedClass dev = new Models.DerivedClass();
Am I missing anything? Thanks in advance.
Inheritance hierarchies are mapped to one DbSet. If you want to filter on inherited entities you can use:
DerivedClass derivedclass = db.BaseClasses.OfType<DerivedClass>().Single(d => d.Id == id);
The OfType<>() filters the object set for instances of the type you specify.
For adding and updating a derived entity you can also the parent DbSet and EF will map it to the correct tables.
Hi there I am hoping someone can point me in the right direction.
I want to create an mvc applicaton I have worked my way through the music store example and still am not 100% sure the correct way to do things.
Lets say I want to create an application that stores cooking receipes.
I have a 3 tables
RecipeTable
RecipeID
RecipeName
RecipeIngredients
RecipeIngredientID
RecipeID
IngredientID
Measurement
IngredientTable
IngredientID
IngredientName
All have PK & FK mappings very basic, I create a new mvc application and use the entity framework to create a new entity e.g. RecipeDB
My next step is I create a new model for each of the tables and give the properties my desired displaynames and specify required fields extra.
Do I then create a viewmodel e.g. RecipesViewModel that looks something like
public class RecipesViewModel
{
public int RecipeID { get; set; }
public string RecipeName { get; set; }
public List<RecipeIngredients> { get; set; }
}
I now create the controller (Ithink) but I am not really sure how to bind that to database entity.
I know you can call the database by doing something like RecipeEntities db = new recipeEntites(); however binding the results to the vm I am little confussed on how to do that.
Am I heading in the right direction so far?
You could use AutoMapper. It's a great tool allowing you to convert from one type to another and in your case from the model to the view model.
public ActionResult Foo()
{
RecipeDB model = _repository.GetRecipies();
RecipesViewModel viewModel = Mapper.Map<RecipeDB, RecipesViewModel>(model);
return View(viewModel);
}
or you could even define a custom action attribute (like the one I used in my sample MVC project) allowing you to simply write:
[AutoMap(typeof(RecipeDB), typeof(RecipesViewModel))]
public ActionResult Foo()
{
RecipeDB model = _repository.GetRecipies();
return View(model);
}
I'm using logical delete in my system and would like to have every call made to the database filtered automatically.
Let say that I'm loading data from the database in the following way :
product.Regions
How could I filter every request made since Regions is an EntitySet<Region> and not a custom method thus not allowing me to add isDeleted = 0
So far I found AssociateWith but I'd hate to have to write a line of code for each Table -> Association of the current project...
I'm looking into either building generic lambda Expressions or.. something else?
You could create an extension method that implements your filter and use that as your convention.
public static class RegionQuery
{
public static IQueryable<Region> GetAll(this IQueryable<Region> query, bool excludeDeleted=true)
{
if (excludeDeleted)
return query.Regions.Where(r => !r.isDeleted);
return query.Regions;
}
}
So whenever you want to query for regions you can make the following call to get only the live regions still providing an opportunity to get at the deleted ones as well.
context.Regions.GetAll();
It my be a little wonky for access the Products property, but still doable. Only issue is you would have to conform to the convention. Or extend the containing class.
someProduct.Regions.GetAll();
I hope that helps. That is what I ended up settling on because I haven't been able to find a solution to this either outside of creating more indirection. Let me know if you or anyone else comes up with a solution to this one. I'm very interested.
It looks to me like you're using a relationship between your Product and Region classes. If so, then somewhere, (the .dbml file for auto-generated LINQ-to-SQL), there exists a mapping that defines the relationship:
[Table(Name = "Product")]
public partial class Product
{
...
private EntitySet<Region> _Regions;
[Association(Storage = "_Regions")]
public EntitySet<Region> Regions
{
get { return this._Regions; }
set { this._Regions.Assign(value); }
}
...
}
You could put some logic in the accessor here, for example:
public IEnumerable<Region> Regions
{
get { return this._Regions.Where(r => !r.isDeleted); }
set { this._Regions.Assign(value); }
}
This way every access through product.Regions will return your filtered Enumerable.