While researching whether or not ASP.NET MVC is suited for my next website, I've come across an annoying issue.
I have followed ASP.NET MVC since version 2, and it's gotten better. For instance, it's now fairly easy to get going with migrations in the entity framework with code first, which used to be a hassle.
This means that I now can get running with a database migrations and code first within half an hour (as I usually don't remember the steps involved, I have to follow a guide I wrote).
Now, fairly early on I always get a many-to-many relationship between entities (e.g. tags and posts) in my database, and what I've found is that getting this relationship exposed via MVC framework is surprisingly complicated! Example from asp.net Example from mikesdotnetting
It involves special methods to retrieve the relationship's data that is not an inherent part of the framework.
Is there really no better/easier way of treating the many-to-many relationship?
You should add a virtual key word to the Many port
public class Post
{
[Key]
public int ID { get; set; }
public string Title { get; set; }
public virtual ICollection<Tag> Tags {get;set;}
}
public class Tag
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Post> Posts {get;set;}
}
Related
For example: I need to display comments from Comments table in database.
So in DAL project I have POCO class:
public class Comments
{
public int CommentId { get; set; }
public string Author { get; set; }
public string Content { get; set; }
}
In BLL project I have class (DTO - data transfer object):
public class CommentsDTO
{
public int CommentId { get; set; }
public string Author { get; set; }
public string Content { get; set; }
}
So I get IEnumerable from DAL, convert to IEnumerable and return it to Web project.
In Web project I have class:
public class CommentsViewModel
{
public int CommentId { get; set; }
public string Author { get; set; }
public string Content { get; set; }
}
So in Web project I get IEnumerable from BLL, convert to IEnumerable and return it to view.
Is it correct? Because these classes have only different names.
It is certainly incorrect and you should not do this generally ad this just duplicates the code. You need different classes only when they differ. Suppose that you want to display a Comment in your web application and Comment is associated with User entity. Then, instead of sending 2 object separately you just create DTO class that combines properties of the two (like comment text and user name). Then sometimes you need to change the model in your web application to display data properly. For instance you want to display them in grid, and to do that properly you need to assign some attributes over properties and this is a good reason to create separate model in your web application. If you do not need to change your classes you should reuse existing ones. However even in your case changing CommentsViewModel a bit might be beneficial - usually you do not want user to see CommentId value (this is db internal thing) - so you can this field in [HiddenInput(DisplayValue = false)] so you could use Html.EditorForModel just to display editor panel. But this is your choice.
Creating each class for every layer is certainly beneficial for large projects. When I say large, I mean exceeding 5 developers with a application lifetime of 10 years. On large projects, the disadvantage of duplication becomes small compare to the benefit it provides.
For small projects, it is certainly overkill. The extra weight will slow you down with little or no benefit. Its like packing 7-day clothes on a 2 day hiking trip.
The larger the project, the more formal is your architecture.
With that said, here is my advice:
The Comment should be shared by the DAL and Business Layer.
If you don't have a "service layer", loose the DTO classes and map the Comment straight to the CommentViewModel. More about the service layer
I say Comment without "s" because only classes that represents collections should be named plural.
I have been scouring forums and repository pattern blogs for some clear direction on how I should be coding my project and I'm stuck. Any help or guidance from you guys would be much approciated :)
I started my project as EF5 MVC4 Razor Code First and decided to use MVCScaffolding to generate all my controllers, views and repositories. This was my first project with these technologies, I was just told that this was how the team was doing it now (but the previous developers did model first and hand coded their contexts).
SO, all is great, we're coding a bunch of screens, but one of our screens is a complex one that involves many models/sub modlels (ie/ Object model has FKs to Responses, Attachments, Reviewers, etc...). The user adds a bunch of data, selects one or more reviewers, adds 0 or more attachments. Then they hit Save!
Now my big problem is that I want to save all this data as one transaction, and if something fails on one of the children models (ie/ attachments) the transaction will roll back. However, the way the MVCScaffolding repositories are created, each model has it's own instance of DB Context and it's own Save. And the controllers accept each unique repository as parameters for loading the screen data. Another thing to note is for this screen we are using a ViewModel to load the data, and then wrote custom mappers to map back to the different models for saving. We can save each piece separately, and possibly the solution is just to wrap TransactionScope around my save, but I also want to reduce the number of calls to the db, as each repository save does a call.
I thought I could add code to the parent repository for a UnitsOfWork type save that would add/edit all the child obejcts in one context object, but that seems like a hack more than anything, and I want to code this properly.
One of the other projects here just made a custom DB context and all Save methods were in that class, is that the best way to do it? Another dev did code first but hand coded all his Save methods. None of them are in a standard place and he is using TransactionScope with a DBContext inside (is that overkill or does DBContext not handle transactions)?
Since I'm so new to this, I need help and no one I work with seems to agree on a proper method. I'm not sure if my model is wrong for an "MVC App" since I'm such a database heavy thinker.
Below is a sample of my models, any guidance is appreciated. Thanks :)
public class Anomaly
{
[Key]
public int AnomalyId { get; set; }
public string Subject { get; set; }
public int PlantId { get; set; }
[ForeignKey("PlantId")]
public virtual Plant Plant { get; set; }
public DateTime? ReviewByDate { get; set; }
public virtual ICollection<AnomalyReviewer> AnomolyReviewers { get; set; }
public virtual ICollection<AnomalyAttachment> AnomalyAttachments { get; set; }
}
public class AnomalyAttachment
{
[Key]
public int AnomalyAttachmentId { get; set; }
public int AnomalyId { get; set; }
[ForeignKey("AnomalyId")]
public virtual Anomaly Anomaly { get; set; }
public string FilePath { get; set; }
public string FileName { get; set; }
public string FileExtension { get; set; }
public string Notes { get; set; }
}
ps. that is just a sample... thanks!
Just create a class 'Master' that inherits from Controller.
Then write all your queries there as in public User GetUserById(Int32 id)
Finally create a function that does a call to the private!! implementation of DbContext.
I would usually give that function a enum of SystemEvents so i've got a reference of whats happening if something would fail... of course you would need to write your own notificator or model to record your own errors into the database for personal testing...
ive done all this because I can write all my code and found out that Repository Pattern is overkill most of the time if you actually think about it.
Currently I am building a web application with MVC 4 and Entity Framework code first scenario.
In the main structure of my application, I have a Dbcontext(BlogDB) to manage some Blog classes. It works fine as it created all the tables I need in the database. Then I created a Area to host an online store. My idea is to create a separated DbContext class(OnlineStoreDB) to handle the classes used for Online Store only.
My problem is once the OnlineStoreDB is fired, entity framework not only created tables for OnlineStore BUT ALSO removed old tables.
My questions are:
If you know a way to keep the old tables?
How exactly to manage the multi EF context classes in one application?
Code:
public class BlogDB : DbContext
{
public BlogDB ()
: base("DBConnection")
{
Database.SetInitializer(new BlogInitializer());
}
public DbSet<Blog> Blogs { get; set; }
public DbSet<Author> Authors { get; set; }
public DbSet<Comment> Comments { get; set; }
}
public class OnlineStoreDB : DbContext
{
public OnlineStoreDB() :
base("DbConnection")
{
Database.SetInitializer(new OnlineStoreInitializer());
}
public DbSet<Order> Orders { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<User> Users { get; set; }
}
Xavier, welcome to code-first!
Yes, code-first was a brilliant approach that promised soooo much. But now you've hit the catch. There's no clever mind at Microsoft (or outside as far as I know) who has come up with a smooth way to alter tables intelligently without endangering the data and possibly schema.
2 Years ago, the implementation strategy was to drop and re-build the DB. That was just intolerable as many of us didn't have SU access and were stopped in our tracks.
For all the advantages I found from code first, I prefer DB first. While data can't be preserved easily, annotations can through buddy classes.
Microsoft has come up with some clever Migration Strategies. I strongly suggest you read both articles. Code Project 2nd:
1) http://blogs.msdn.com/b/adonet/archive/2012/02/09/ef-4-3-code-based-migrations-walkthrough.aspx
2) http://www.codeproject.com/Articles/504720/EntityplusFrameworkplusCodeplusFirstplusMigrations
whether you decide to continue with Code-First, they should be enlightening. I sound like a critic but I'm torn between advantages of one and stability of the other.
Finally, I don't think you should preserve 2 dbcontexts. Your POCOs should be consolidated under 1 context.
If you want to keep the tables not changed you need to set initializer to null in both DBContexts if they have sub set of tables .
But I don't see a point that you create two DBContexts for one database. Can you clearly separate two set of tables(Domains) in you database?
I am in the planning phase of a new ASP.NET MVC application and one of the requirements is storing some user information that is not part of the standard set found in the User class that comes with ASP.NET MVC. I suppose it comes down to two questions.
1) Can I edit the class that is being used already to store the information that I need?
2) If I roll my own how can I keep things like the Authentication piece that make things so nice when trying to lock down some views using the User.IsAuthenticated method?
Another alternative I have considered is using the User class provided as is, and instead putting the other information into a separate table with the guid userid as the foreign key.
Suggestions?
Profiles are one option as #Burt says, and offers a lot of flexibility.
I had a similar need to track Employee information, but I opted to roll my own Employee class and create a relationship to a standard User. I really like how this has worked out as I can keep any Employee specific business logic separate from the User class Membership system.
Since not every User was going to be bound with an employee, this made more sense for my case. It may not for yours, but it is an alternative.
So, I have something like:
public class Employee
{
public Employee(string name) : this()
{
Name = name;
}
public virtual string Name { get; set; }
public virtual string Title { get; set; }
public virtual decimal Salary { get; set; }
public virtual decimal Hourly { get; set; }
public virtual decimal PerDiem { get; set; }
public virtual string StreetAddress { get; set; }
public virtual Guid UserId { get; set; }
public virtual MembershipUser User {
get
{
// note that I don't have a test for null in here,
// but should in a real case.
return Membership.GetUser(UserId);
}
}
}
See ASP.Net MVC Membership Starter Kit. It provides the Asp.Net MVC controllers, models, and views needed to administer users & roles. It will cut distance in half for you.
Out of the box, the starter kit gives you the following features:
List of Users
List of Roles
User
Account Info
Change Email Address
Change a User's Roles
Look into profiles that are part of the membership functionality provided by MS. They are extendable and pretty flexible.
I am creating a Web application using ASP.NET MVC, and I'm trying to use domain-driven design. I have an architecture question.
I have a WebControl table to store keys and values for lists so they can be editable. I've incorporated this into my business model, but it is resulting in a lot of redundant code and I'm not sure it belongs there. For example, in my Request class I have a property called NeedType. Because this comes from a list, I created a NeedType class to provide the values for the radio buttons. I'm showing just one example here, but the form is going to have probably a dozen or so lists that need to come from the database.
[edit, to clarify question] What's a better way to do this? Are these list objects really part of my domain or do they exist only for the UI? If not part of the domain, then they don't belong in my Core project, so where do they go?
public class Request : DomainObject
{
public virtual int RequestId { get; set; }
public virtual DateTime SubmissionDate { get; set; }
public virtual string NeedType { get; set; }
public virtual string NeedDescription { get; set; }
// etc.
}
public class NeedType : DomainObject
{
public virtual int NeedTypeId { get; set; }
public virtual string NeedTypeCode { get; set; }
public virtual string NeedTypeName { get; set; }
public virtual int DisplayOrder { get; set; }
public virtual bool Active { get; set; }
}
public class RequestController : Controller
{
private readonly IRequestRepository repository;
public RequestController()
{
repository = new RequestRepository(new HybridSessionBuilder());
}
public RequestController(IRequestRepository repository)
{
this.repository = repository;
}
public ViewResult Index(RequestForm form)
{
ViewData.Add("NeedTypes", GetNeedTypes());
if (form == null)
{
form = new RequestForm();
form.BindTo(repository.GetById(125));
}
}
private NeedType[] GetNeedTypes()
{
INeedTypeRepository repo = new NeedTypeRepository(new HybridSessionBuilder());
return repo.GetAll();
}
}
Create a seperate viewmodel with the data you need in your view. The Model in the M of MVC is not the same as the domainmodel. MVC viewmodels are dumb DTO's without behaviour, properties only. A domain model has as much behaviour as possible. A domain model with get;set; properties only is considered an anti-pattern called "anemic domain model". There are 2 places where most people put the viewmodels: in the web layer, close to the views and controllers, or in a application service layer.
Edit:
When you only need to display a list of all needtypes in the database and one request in your view, I would indeed create one viewmodel with the request and the list of needtypes as properties. I don't think a call to multiple repositories in a controller is a smell, unless you have a larger application and you might want a seperate application service layer that returns the whole viewmodel with one method call.
I think it might also be a good idea to follow the advise of Todd Smith about value object.
When the needtypes can be added or edited by users at runtime, needtype should be an entity. When the needtypes are hardcoded and only changed with new releases of the project, needtype should be a value object and the list of needtypes could be populated by something like NeedType.GetAll() and stored in the database by adding a column to the request table instead of a seperate needtype table.
If it comes from a list, then I'm betting this is a foreign key. Don't think about your UI at all when designing your domain model. This is simply a case where NeedType is a foreign key. Replace the string NeedType with a reference to an actual NeedType object. In your database, this would be a reference to an id.
When you're building your list of NeedType choices, you simply need to pull every NeedType. Perhaps keeping it cached would be a good idea if it doesn't change much.
Your NeedType looks like a value object to me. If it's read-only data then it should be treated as a value object in a DDD architecture and are part of your domain.
A lot of people run into the "omg so much redundancy" issue when dealing with DDD since you're no longer using the old Database -> DataTable -> UI approach.