I have gone through a lot of documents and found several ways of trying to make a CreateViewModel.
I want to know what does ICollection Does.
public Payment{
public int ID {get; set;}
public string Details {get; set;}
public virtual ICollection<Expense> Expenses {get; set;}
}
public Expense{
public int ID {get; set;}
public string MyDetails {get; set;}
}
So I guess in my View, I can Use just the plain class as virtual to make a Create Method. But if I want to use ViewModel to make a view with 2 or more DataModels for Creation. How will I go with that. Cause I guess I can always just make a
public virtual Payment payments {get; set;}
public virtual Expense expenses {get; set;}
But I am trying to ready this for Dynamically Having a Add Button Generating an Expense Details Input.
Not to mention, the IEnumerable as well, but I guess this needs an ID more suitable for Editing and Details for what I understand.
All you need is a PaymentViewModel class, where you'll use List<Expense> instead of ICollection<Expense>:
public class PaymentViewModel
{
// ID property unnecessary here because it doesn't need
// to be posted from the form
public string Details { get; set; }
// You may want to use something like `List<ExpenseViewModel>`
// based on your needs
public List<Expense> Expenses { get; set; }
}
With that, you add additional expense records to your form by making sure the input names are in the format of Expenses[N].MyDetails, where N is the index. Whatever JavaScript solution you use to add additional expense records to the form should create these inputs with properly indexed names. This would be a good place to use a JavaScript templating solution, or something that handles data-binding like Knockout.
For editing existing expenses, should you have the need, you just generate the fields like with any collection, but you need to use a for loop rather than the more traditional foreach:
#for (var i = 0; i < Model.Expenses.Count(); i++)
{
#Html.EditorFor(m => m.Expenses[i].MyDetails)
}
As a side note, since you asked, ICollection<T> is the required type for entity navigation properties with Entity Framework. These reasons are very low level, but has to do with the way Entity Framework handles one-to-many and many-to-many relationships at an object level and issues such as lazy loading. However, ICollection<T> doesn't work for actually submitting items through an HTML form, due mostly to the fact that it's not indexable. That's why a view model is so important in this scenario.
Related
in .net core 3.1
if i has a model class that has a navigation property inside of it,
public class Department
{
public int ID { get;set; }
public string Name { get; set; }
public List<Student> Students { get; set; }
}
public class Student
{
public int ID { get; set;}
public string Name { get; set;}
}
According to the models before what is the difference between .AsNoTracking() and with tracking related to the Navigation Property
For Example
if i retrieve object of Department with no tracking will it populate the Student list or not and the same for withTracking
and another thing is
if i want to update the Department without affecting the Student list inside of it, how should i achieve that.
and last this because i have been through the docs without understanding
what EntityState.Detached means
and the difference between DBSet.Attach() and DBSet.Update()
There is a fairly good article that describes the behavior of tracking here: https://learn.microsoft.com/en-us/ef/core/querying/tracking.
As for Detach/Attach you can use the following as a guide. The example will provide some commentary around its usage.
https://learn.microsoft.com/en-us/dotnet/api/system.data.objects.objectcontext.detach?view=netframework-4.8
https://learn.microsoft.com/en-us/dotnet/api/system.data.objects.objectcontext.attach?view=netframework-4.8&viewFallbackFrom=netcore-3.1
As for updating without affecting the students what I usually do is make sure that I use the .Include(x=> x.Students) then perform the update on the entity object I am interested in and save those changes to the context.
Lastly there is a fantastic book that you can also read called Entity Framework Core in action. I found it very helpful when starting out with EF.
Hope this helps. Good Luck.
I have a model that has some related data in navigation properties, like so:
public class Document
{
[Key]
public int DocumentId { get; set; }
public string DocumentName { get; set; }
public virtual ICollection<DocumentBeneficiary> DocumentBeneficiaries { get; set; }
public virtual ICollection<DocumentExecutor> DocumentExecutors { get; set; }
public virtual ICollection<DocumentSuccessor> DocumentSuccessors { get; set; }
}
I understand how to do eager loading of this related data from a controller method, like so:
var doc = context.Documents.Include(x => x.DocumentBeneficiaries)
However, what I want to do is write a member method inside the model that takes the data related to an entity, does some processing, and outputs a string. Something like this:
public class Document
{
...
public string ProcessStuff() {
//use data in navigation properties here like so:
foreach (var d in DocumentBeneficiaries) { ... }
}
}
Is this allowable? I can't seem to find anything about it on google. Will it load the related data lazy vs. eager depending on how I load the entity in the controller prior to calling the method in the model?
I realize that some schools of thought hold that models should have no methods, but others say it's ok to put business logic in the model. If I have to I suppose I can make this a controller method, but this way makes more sense to my design if possible. Sorry if this is a somewhat speculative question, but I can't seem to find any info on this pattern.
Yes it will load the DocumentBeneficiaries when you invoke ProcessStuff method as long as Lazyloading is enabled, thou it may not be a good design (my opinion) to add business logic directly into the model, but as you stated, there are some who like it and some who don't.
If you don't load the child collection ahead of time using Include and Lazyloading is enabled, then you will end up making extra database trips while executing ProcessStuff(). Using Include pre loads the data you need with less number of database round trips. It is always better to make less database trips whenever possible.
If Lazyloading is disabled, you have to use Include before invoking ProcessStuff()
I've just read quite a few posts on Table per Type/TPT and the discriminator column, but, I'm not really any the wiser in my situation.
Taking an example: I have a MVC app that has a model called Foo. This has one property called Bar that is stored as a one to many elsewhere.
I am the only one using this app and I didn't want to spend a lot of time on it, so I just wanted the quickest way to add items to the list in Bar. Because of this, I made a new class called FooViewModel that is derived from Foo, and had a string property called BarTemp.
The basic idea is that I can type 111, 222 , 333,444 in to a standard text field and have the edit/create controllers clear whitespace and split to a list on the comma.
What I can't figure out is that the view model will never be written to EF, so, why is it creating the discriminator column.
It looked like when I tried to scaffold a migration, it event tried adding BarTemp to the DB.
I have since created a new type called the same, but instead of deriving, I just have Foo and BarTemp as properties in it which works as expected, but, I still don't get what happened and would like to learn more.
It's because EntityFramework parses the hierarchy. Just because your current code doesn't ever save a BarTemp, there's nothing explicitly stopping you from writing:
context.Bars.Add(new BarTemp());
There's nothing EntityFramework can do to detect the above. So, it plays safe and assumes that if you inherit from an entity, your subclass will also be an entity. That's a correct assumption - and you shouldn't make view models inherit from the entity. Neither should they be properties. I'm really unsure how you've setup your current code, but the classes should be completely distinct. For example, it should look something like:
class BarTemp
{
public string BarId { get; set; }
public string Foos { get; set; }
}
class Bar
{
public string BarId { get; set; }
public ICollection<Foo> Foos { get; set; }
}
class Foo
{
public string Id { get; set; }
public Bar Bar { get; set;
}
Your view model should know nothing about the entities, and the entities should know nothing about the view models. Your code accepting the input should do the work converting the view model to the entity. For example:
private void Update(BarTemp barTemp)
{
var bar = context.Bars.GetById(barTemp.BarId);
foreach (var foo in barTemp.Foos.Split(","))
{
var foo = context.Foos.GetById(foo);
bar.Foos.Add(foo);
}
context.Save();
}
Don't take the above as an example of good code - it's extremely inefficient - but it should show you an example of where the conversions should take place, and how to keep the entities and view models separate.
I have the following ViewModel:
public class InvitationViewModel
{
public int id { get; set; }
public string InvitationName { get; set; }
public string Type { get; set; }
public string RSVPStat { get; set; }
public virtual List<Guests> guests { get; set; }
}
I want to add some validation for the List of Guests, is it possible to use data annotations for this or is there some other way?
Thanks for any suggestions.
Since your question is a little unclear, I'll round the bases. You can add some validation to the list itself, if that's what you're looking for. That pretty much just includes Required, which would validate that the list has at least one item:
[Required]
public List<Guests> Guests { get; set; }
The keyword virtual allows a property, method or field to be overridden by a subclass. Most likely, you saw this on your entity and figured you need the same here in your view model. The reason entities use virtual on reference and navigation properties is that Entity Framework creates proxy classes of your entities in order to provide lazy-loading functionality. The proxies (which are just subclasses) override the reference and navigation properties to insert the lazy-loading code necessary.
If you're talking about adding validation attributes to the properties of the actual Guest class, you cannot do that just for the sake of a view model. Any validation you add to Guest will be for any use of Guest. There's nothing stopping you from also implementing a GuestViewModel or similar class, though, which you could then add whatever validation you like to.
Do you want to validate each guest? In that case mark Guest up with Data annotations. If you want a validation on the list itself (i.e. number of guests), you can write you own ValidationAttribute, or you can implement IValidateableObject on your model.
Edit: if your view model requires different validation, create a GuestViewModel and mark it up with the required validation.
Right now I have proxy creation disabled:
context.Configuration.ProxyCreationEnabled = false;
I have a data model like so (removed non-relevant fields):
public partial class Video
{
public int VideoID { get; set; }
public string Title { get; set; }
public int UserID { get; set; }
public virtual User User { get; set; }
}
public partial class User
{
public User()
{
this.Videos = new HashSet<Video>();
}
public int UserID { get; set; }
public string Username { get; set; }
public virtual ICollection<Video> Videos { get; set; }
}
I am using Unit of Work and Repository patterns to load my data like so,
Get all video's, including the user object:
var videos = videoService
.Include(v => v.User)
.Get()
I am using automapper to map from data model to domain model (hence the UI namespace in the screenshot below). When I inspect the video enumeration I get back, and look at the first item in the enumeration, I go to check the user object:
What I expect here is the VideoModel to be filled with data(ok), with only it's single UserModel entity to be filled with data(ok), and all collections in the UserModel to be empty(this is broke). As you can see in the second red box above, the Videos collection is populated with 6 videos. And on those video's, the user's are filled in. So this basically creates a very large object graph.
1) Can I make it so when using an include that it ONLY goes 1 level deep (IE doesn't fill in Video.User.Videos)?
2) Why doesn't ProxyCreationEnabled = false take care of this? Am I expecting too much?
p.s. I want to avoid creating a customer mapper for this with automapper.
p.p.s. I am doing db first, not model first
By default, EntityFramework uses lazy loading for virtual properties (such as User and Videos in your example). If you want these properties to be filled prior to them actually being accessed, you can use Include() or, to go another level deep, an Include() with a nested Select().
This default behavior, however, relies on the creation of a proxy class, which you have apparently turned off.
Not knowing all the things you're trying to do, this may not work, but it seems like you would get the behavior you wanted by simply removing ProxyCreationEnabled = false and using Include() as you have.
Also, viewing properties in the debugger may be misleading because you are in fact accessing the property when you try to view it in the debugger (which could cause the lazy loaded entity or collection to be filled right then, making you think it had been eagerly loaded).