How to include multiple child objects? - asp.net

I'm playing with new ASP.Net 5.0 WebApi and strugling to understand how to return more then one child object, or child of the child.
Lets say I have 4 classes:
public class Car
{
public int Id { get; set; }
public string Name { get; set; }
public int TypeId { get; set; }
public int ColourId { get; set; }
public virtual Type Type { get; set; }
public virtual Colour Colour { get; set; }
}
public class Type
{
public int Id { get; set; }
public string Name { get; set; }
public int TypeGroupId { get; set; }
public virtual TypeGroup TypeGroup { get; set; }
}
public class Colour
{
public int Id { get; set; }
public string Name { get; set; }
}
public class TypeGroup
{
public int Id { get; set; }
public string Name { get; set; }
}
And would like to return all the data for the car including Type, Colour, and even TypeGroup of the Type. How do I Do it?
When I do like this it includes only Type:
[HttpGet]
public IEnumerable<Car> Get()
{
return _dbContext.Cars.Include(c => c.Type);
}
This is my setup in Startup.cs:
services.AddMvc().AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver =
new CamelCasePropertyNamesContractResolver();
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
Is it possible to set to return every child object and grandchild and etc?
Many thanks

You can turn off lazy loading for all entities by using the following in your DbContext class (place this in the constructor):
this.Configuration.LazyLoadingEnabled = false;
This will disable it for all entities - so be wary of this and watch for performance issues.
Another way you can load all the entities for a particular class is to remove the virtual keyword from the property declarations.

Related

Best way to create a map between two entities with a third one from another context

Hi I'd like to create a map between two entities (source: User, target: UserInfosDto) while one member of the target DTO (UserItemPreference) needs info from a third entity inside another context.
public class UserInfosDto
{
//public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public UserItemPreferencesDto UserItemPreferences { get; set; }
}
public class UserItemPreferencesDto
{
public bool SeeActuality { get; set; }
public bool IsInEditorMode { get; set; }
}
public class User
{
public string IdentityId { get; set; }
//...
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
public class UserIdentity
{
public string IdentityId { get; set; }
//...
public bool SeeActuality { get; set; }
public bool IsInEditorMode { get; set; }
}
User and UserIdentity come from different databases but have a common property IdentityId. I thought about using ITypeConverter in which I would inject the UserIdentity dbContext. Problem is that I can't find a way to use ITypeConverter on one member only.
Use an IValueResolver instead, which allows to resolve separate members instead of full types.
For your case above it will look like
public class UserItemPreferencesResolver
: IValueResolver<User, UserInfosDto, UserItemPreferencesDto>
{
private readonly UserEntityDbContext _dbContext;
public UserItemPreferencesResolver(UserEntityDbContext dbContext)
{
_dbContext = dbContext;
}
public UserItemPreferencesDto Resolve(
User source,
UserInfosDto destination,
UserItemPreferencesDto destinationMember,
ResolutionContext context
)
{
UserItemPreferencesDto preferences = /* resolve from _dbContext (and transform) */
return preferences;
}
}
Your create the mapping via
CreateMap<User, UserInfosDto>()
.ForMember(
dest => dest.UserItemPreferences,
opt => opt.MapFrom<UserItemPreferencesResolver>()
);

Map reference property fields to the same table as root class

I have the model with reference properties
internal class AstronomycalBody : IAstronomycalBody
{
public long Id { get; set; }
public string Name { get; set; }
public Coord Coord { get; set; }
public long Mass { get; set; }
public double Speed { get; set; }
public IAstronomycalBody CentralObject { get; set; }
}
public class Coord
{
public long X { get; set; }
public long Y { get; set; }
public long Z { get; set; }
}
I want to use mapping like this
internal class AstronomycalBodyContext : DbContext
{
public DbSet<AstronomycalBody> AstronomycalBody { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite(DbSettings.ConnectionString);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<AstronomycalBody>().Property(p => p.Coord.X).ForSqliteHasColumnName("CoordX");
modelBuilder.Entity<AstronomycalBody>().Property(p => p.Coord.Y).ForSqliteHasColumnName("CoordY");
modelBuilder.Entity<AstronomycalBody>().Property(p => p.Coord.Z).ForSqliteHasColumnName("CoordZ");
modelBuilder.Entity<AstronomycalBody>().Property(p => p.CentralObject.Id).ForSqliteHasColumnName("CentralObjectId");
}
}
to map the model on this table:
Currently, the compiler is throwing this exception...
Your AstronomycalBody is not a valid EF entity model class.
First, EF Core does not support Complex/value types yet, so the Coord member should be expanded in place.
Second, EF does not work with interfaces, so every navigation reference / collection element type should be entity class.
With that being said, not sure how your IAstronomycalBody looks like and how you can implement it (you might need explicit implementation of some members), but the entity class should be like this:
internal class AstronomycalBody //: IAstronomycalBody
{
public long Id { get; set; }
public string Name { get; set; }
//public Coord Coord { get; set; }
public long CoordX { get; set; }
public long CoordY { get; set; }
public long CoordZ { get; set; }
public long Mass { get; set; }
public double Speed { get; set; }
public AstronomycalBody CentralObject { get; set; }
}
Now, since by convention it will generate the exact table shown, simply remove all shown lines in OnModelCreating and you are done.

How to make single view using viewmodel in asp.net mvc 4?

I have different models Image,Page & PageCategories
public class Image
{
public int ImageId { get; set; }
public string ImageTitle { get; set; }
public string ImageURL { get; set; }
}
public class Page
{
public int PageId { get; set; }
public string PageTitle { get; set; }
public string Content { get; set; }
public int PageCategoryId { get; set; }
public virtual PageCategory PageCategory { get; set; }
}
public class PageCategory
{
public int PageCategoryId { get; set; }
public string CategoryName { get; set;
public virtual ICollection<Page> Pages { get; set; }
}
DBContext Class is
class DemoContext:DbContext
{
public DbSet<PageCategory> PageCategories { get; set; }
public DbSet<Page> Pages { get; set; }
public DbSet<Image> Images { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
I am wondering how to get all the model data to the home page using ViewModel.
For Ex.:
How to get image list and Page list in home page from multiple models?
You may want something like this :
viewModel :
//Create a viewModel with all the properties that you need
public class ViewModel
{
public int ImageId { get; set; }
public string ImageTitle { get; set; }
public string ImageURL { get; set; }
public int PageId { get; set; }
public string PageTitle { get; set; }
public string Content { get; set; }
public int PageCategoryId { get; set; }
public string CategoryName { get; set; }
}
Controller :
...
using (DemoContext db = new DemoContext()){
List<ImagePageViewModel> viewData = (from p in db.Page
join pc from db.PageCategory on p.PageCategoryId equals pc.PageCategoryId
select new ViewModel(){
PageTitle=p.PageTitle,
CategoryName = pc.CategoryName
//... set every property you want
})
}
return View(viewData );
note: I didn't add Image to the query because there is no explicit relation
between Image and the others table so i let you do it.
Create another class and define all above three into it. like below
public class MyView
{
public List<Image> Images { get; set; }
public List<Page> Pages { get; set; }
public List<PageCategory> PageCategories { get; set; }
}
Controller Action:-
public ActionResult Index()
{
MyView myView = // Get it using your logic
return View(myView);
}
finally got my answer:
public class ViewModelDemo
{
public IEnumerable<Image> images { get; set; }
public IEnumerable<Pages> pages { get; set; }
public IEnumerable<PageCategory> pagecategories { get; set; }
}
Then in HomeController
private DemoContext db=new DemoContext();
public ActionResult Index()
{
ViewModelDemo vm = new ViewModelDemo();
vm.images = db.Images.ToList();
vm.pages=db.Pagess.ToList();
vm.pagecategories=db.PageCategories.ToList();
return View(vm);
}

Automapper configuration for object

I have these classes
public class NamedEntityViewModel
{
public string Name { get; set; }
}
public class NamedEntityListViewModel
{
public List<NamedEntityViewModel> List { get; set; }
}
public class Album : INamedEntity
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<Song> Songs { get; set; }
[Required]
public int AlbumNumber { get; set; }
}
I have a List<Album> and I want to map that to NamedEntityListViewModel with NamedEntityViewModel.Name mapping to Album.Name. How do I set this up in Automapper?
Try something like that:
First create you mapper:
Mapper.CreateMap<Album, NamedEntityViewModel>();
For the mapping do this:
// yourAlbumList is a List<Album>
var albumListVm = new NamedEntityListViewModel();
albumListVm.List = Mapper.Map<IEnumerable<NamedEntityViewModel>>(yourAlbumList);
This should do the job

Using ComplexType with ToList causes InvalidOperationException

I have this model
namespace ProjectTimer.Models
{
public class TimerContext : DbContext
{
public TimerContext()
: base("DefaultConnection")
{
}
public DbSet<Project> Projects { get; set; }
public DbSet<ProjectTimeSpan> TimeSpans { get; set; }
}
public class DomainBase
{
[Key]
public int Id { get; set; }
}
public class Project : DomainBase
{
public UserProfile User { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public IList<ProjectTimeSpan> TimeSpans { get; set; }
}
[ComplexType]
public class ProjectTimeSpan
{
public DateTime TimeStart { get; set; }
public DateTime TimeEnd { get; set; }
public bool Active { get; set; }
}
}
When I try to use this action I get the exception The type 'ProjectTimer.Models.ProjectTimeSpan' has already been configured as an entity type. It cannot be reconfigured as a complex type.
public ActionResult Index()
{
using (var db = new TimerContext())
{
return View(db.Projects.ToList);
}
}
The view is using the model #model IList<ProjectTimer.Models.Project>
Can any one shine some light as to why this would be happening?
Your IList<ProjectTimeSpan> property is not supported by EF. A complex type must always be part of another entity type, you cannot use a complex type by itself. If you absolutely need to have ProjectTimeSpan as a complex type, you will need to create a dummy entity type that only contains a key and a ProjectTimeSpan, and change the type of Project.TimeSpans to a list of that new type.

Resources