This is something that has bugged me since the shift to EF 6. How do we now map collections through to view models such that mapping changes back are not painful using IEnumerables. Here is a code snippet below demonstrating my problem:
Entity - SS.Entity.Event
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<SS.Entity.User> Broadcasters { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<SS.Entity.User> Viewers { get; set; }
Model - SS.Model.Event
public virtual ICollection<SS.Model.User> Broadcasters { get; set; }
public virtual ICollection<SS.Model.User> Viewers { get; set; }
Mapping Back to Entity After Modification of Collection
Broadcasters = e.Broadcasters.Select(u => new SS.Entity.User
{
Id = u.Id,
SkypeId = u.SkypeId,
Name = u.Name
}).ToList(), // THIS IS THE PROBLEM
Viewers = e.Viewers.Select(u => new SS.Entity.User
{
Id = u.Id,
SkypeId = u.SkypeId,
Name = u.Name
}).ToList() // THIS IS THE PROBLEM
The problem with this is I cannot map an ICollection to another ICollection as Select produces an IEnumerable which makes mapping back properties to EF afterwards a pain as I have to recreate the collection or enumerate it to update it. I know I'm missing something obvious, I have updated the ICollection's to be virtual as outlined in other answers but it is unclear to me how this helps.
Any help would be greatly appreciated!
Gerard
Lazy loading means delaying the loading of related data, until you specifically request for it. When using POCO entity types, lazy loading is achieved by creating instances of derived proxy types and then overriding virtual properties to add the loading hook.
Disable Lazy Loading To turn off lazy loading for a particular property, do not make it virtual. To turn off lazy loading for all entities in the context, set its configuration property to false.
The advice is not to use lazy loading unless you are certain that it is the better solution. This is why (unlike in previous versions of EF) lazy loading is not enabled by default in Entity Framework Core.
Lazy loading in Entity Framework is the default phenomenon that happens for loading and accessing the related entities. However, eager loading is referred to the practice of force-loading all these relations.
Assuming your ".ToList()" issue is while saving back to database, is this what your are looking for?:
var event = new SS.Entity.Event {Name = "New Name" and other properties};
IEnumerable<SS.Entity.User> broadcasters = e.Broadcasters
.Select(u => new SS.Entity.User
{
Id = u.Id,
SkypeId = u.SkypeId,
Name = u.Name
});
var viewers = e.Viewers.Select(u =>
new SS.Entity.User
{
Id = u.Id,
SkypeId = u.SkypeId,
Name = u.Name
});
//add broadcasters to event
event.Broadcasters.AddRange(broadcasters);
//add viewers to event
event.Viewers.AddRange(viewers);
dataContext.Events.Add(event);
dataContext.SaveChanges();
On your ViewModel, they can just be IEnumerable<T>
, unless you need to be doing a .Add()
on them later. That can be whatever you want to be. Also, they do not have to be virtual on the Model because you're not having EF create a derived type of your model (again, unless you have other reason to).
To set them back to what they are in the DTO object, if you just want to set it directly and not check individual properties, you can use .ToList()
to have it fulfill the ICollection<T>
requirement.
// Assuming "var model" is coming in as a parameter
var station = context.Viewers.First();
station.Broadcasters = model.Broadcasters.Select(b => new User {
Id = b.Id,
SkypeId = b.SkypeId,
Name = b.Name
}).ToList();
station.Viewers = model.Viewers.Select(v => new User {
Id = v.Id,
SkypeId = v.SkypeId,
Name = v.Name
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With