I have 2 models : Account and Task
public class Account
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Key]
public Guid UserId { get; set; }
public string UserType { get; set; }
public string Name { get; set; }
}
public class Task
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int id { get; set; }
[Key]
public Guid TaskId { get; set; }
[ForeignKey("TaskSubType")]
public Guid TaskSubTypeId { get; set; }
public virtual TaskSubType TaskSubType { get; set; }
[ForeignKey("Account")]
public Guid TaskCreator { get; set; }
public virtual Account Account { get; set; }
}
I call getTasks:
public List<TaskOverViewViewModel> GetTasks()
{
IEnumerable<Task> result = db.Tasks.AsEnumerable();
List<TaskOverViewViewModel> list = ToViewModelMapper.toViewModel(result);
return list;
}
public class ToViewModelMapper
{
internal static List<TaskOverViewViewModel> toViewModel(IEnumerable<Task> entitys )
{
List<TaskOverViewViewModel> modelList = new List<TaskOverViewViewModel>();
foreach (var entity in entitys)
{
TaskOverViewViewModel model = new TaskOverViewViewModel();
model.SubTaskName = entity.TaskSubType.Name;
model.TaskCreator = entity.Account.LoginName;
model.ToolsAccesable = entity.ToolsAccesable;
modelList.Add(model);
}
return modelList;
}
}
But it fails because i entity.TaskSubType and entity.Account is null. But if i return IEnumerable<Task> result = db.Tasks.AsEnumerable(); in the call everything works fine and i can see that Json contains all TaskSubtype and Account models.
From linq-to-entities, you can project directly to your ViewModel class.
public List<TaskOverViewViewModel> GetTasks()
{
List<TaskOverViewViewModel> result = (from t in db.Tasks
select new TaskOverViewViewModel
{
SubTaskName = t.TaskSubType.Name;
TaskCreator = t.Account.LoginName;
ToolsAccesable = t.ToolsAccesable;
}).ToList();
return result;
}
If you prefer method syntax, you can use this:
List<TaskOverViewViewModel> result = db.Tasks.Select(t => new TaskOverViewViewModel
{
SubTaskName = t.TaskSubType.Name;
TaskCreator = t.Account.LoginName;
ToolsAccesable = t.ToolsAccesable;
}).ToList();
Related
I have the classes below:
public class User
{
public Guid Id { get; set; }
public string Name { get; set; }
}
public class ParentEntity
{
public Guid Id { get; set; }
public string SomeProperty { get; set; }
public ICollection<ChildEntity> ChildEntities { get; set; }
}
public class ChildEntity
{
public Guid Id { get; set; }
public int Vote { get; set; }
public Guid UserId { get; set; }
}
public class ReturnedParentDto
{
public Guid Id { get; set; }
public string SomeProperty { get; set; }
public int Vote { get; set; }
}
I want to be able to return a full list of ParenEntities, but take an Id of the User class (UserClassId), then filter the ParentEntity's ICollection where UserUid = UserClassId, so only 1 ChildEntity is always returned. Then I would want to extract a specific field from that returned ChildEntity and merge it with the ParentEntity fields. The end result should be like the ReturnedParentDto.
I want to do it in the style like
ParentEntities.Include(v => v.ChildEntities).ToList()
That seems to be possible in EF Core 5, but my project is in 3.1.
You can do this as below
Approach 1:
var result = result = parentEntities.Include(x => x.ChildEntities.Where(y => y.UserId == userId))
.Select(x => new ReturnedParentDto {
Id = x.Id,
SomeProperty = x.SomeProperty,
Vote = x.ChildEntities.FirstOrDefault()?.Vote // userId is the variable here
});
Approach 2:
var result = parentEntities.Select(x =>
new ReturnedParentDto {
Id = x.Id,
SomeProperty = x.SomeProperty,
Vote = x.ChildEntities.FirstOrDefault(y => y.UserId == userId)?.Vote // userId is the variable here
});
I am working on a .NET Core Web API
So far I used to return anonymous types in my controllers but now I want to start using the full power of swagger with auto documentation of the return types.
Which lead me to start using view models.
But I am struggling with converting between the auto-generated database model classes
and the auto-generated swagger view model classes.
It works for a single instance (see GetPerson method in the controller below) but fails when I want to return lists.
So my questions:
How do I cast/convert collections/lists of objects between view models and database models
Is the code in the controller correct? Are there easier/shorter/better ways to do the conversion? (I read about using the implicit operator)
Error message I get:
Cannot implicitly convert type 'System.Linq.IQueryable' to 'System.Collections.Generic.List'. An explicit conversion exists (are you missing a cast?)
It gives me an InvalidCastException if I cast them explicitly like
List result = (List)_dbContext.Person....
there seems to be a problem with generics in the display of stackoverflow
Assume I used the generic lists with giving a type PersonView
My code looks like:
Database models
public partial class Person
{
public Person()
{
}
public int Id { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public int? MainAdressId { get; set; }
public virtual Adress MainAdress { get; set; }
}
public partial class Adress
{
public Adress()
{
Person = new HashSet();
}
public int Id { get; set; }
public string CityName { get; set; }
public int CityPostalCode { get; set; }
public string StreetName { get; set; }
public string HouseNumber { get; set; }
public string FloorNumber { get; set; }
public string DoorNumber { get; set; }
public virtual ICollection Person { get; set; }
}
View models
public class City
{
public string Name { get; set; }
public int PostalCode { get; set; }
}
public class Street
{
public string Name { get; set; }
public string HouseNumber { get; set; }
public string FloorNumber { get; set; }
public string DoorNumber { get; set; }
}
public class AdressView
{
public Street Street { get; set; }
public City City { get; set; }
}
public class PersonView
{
public string FirstName { get; set; }
public string Lastname { get; set; }
public AdressView Adress { get; set; }
}
The controller class which is working for a single instance but not for lists
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Swashbuckle.SwaggerGen.Annotations;
using PersonExample.ModelsPersonDB;
using PersonExample.ModelsViewPerson;
namespace PersonExample.Controllers
{
[Route("api/[controller]")]
public class PersonViewTestController : Controller
{
private readonly PersonDBContext _dbContext;
private readonly ILogger _logger;
public PersonViewTestController(PersonDBContext dbContext, ILogger logger)
{
_dbContext = dbContext;
_logger = logger;
_logger.LogDebug("{0} > new instance created", GetType().Name);
}
[HttpGet("{id:int}", Name = "GetPerson")]
[ProducesResponseType(typeof(PersonView), 200)]
[SwaggerOperation("GetPerson")]
public virtual IActionResult GetPerson([FromRoute]int id)
{
PersonView result = _dbContext.Person
.Include(p => p.MainAdress)
.Where(p => p.Id == id)
.Select(p => new PersonView()
{
FirstName = p.Firstname,
Lastname = p.Lastname,
Adress = (p.MainAdress == null) ? null :
new AdressView()
{
Street = new Street()
{
Name = p.MainAdress.StreetName,
HouseNumber = p.MainAdress.HouseNumber,
FloorNumber = p.MainAdress.FloorNumber,
DoorNumber = p.MainAdress.DoorNumber
},
City = new City()
{
Name = p.MainAdress.CityName,
PostalCode = p.MainAdress.CityPostalCode
}
}
}
)
.FirstOrDefault();
return new ObjectResult(result);
}
[HttpGet(Name = "GetPersonList")]
[ProducesResponseType(typeof(List), 200)]
[SwaggerOperation("GetPersonList")]
public virtual IActionResult GetPersonList()
{
List result = _dbContext.Person
.Include(p => p.MainAdress)
.Select(p => new PersonView()
{
FirstName = p.Firstname,
Lastname = p.Lastname,
Adress = (p.MainAdress == null) ? null :
new AdressView()
{
Street = new Street()
{
Name = p.MainAdress.StreetName,
HouseNumber = p.MainAdress.HouseNumber,
FloorNumber = p.MainAdress.FloorNumber,
DoorNumber = p.MainAdress.DoorNumber
},
City = new City()
{
Name = p.MainAdress.CityName,
PostalCode = p.MainAdress.CityPostalCode
}
}
}
);
return new ObjectResult(result);
}
}
}
you can use AutoMapper https://github.com/AutoMapper/AutoMapper/wiki/Getting-started
here some examples: Simple Automapper Example
example with EF core and ASP.NET WebApi: https://github.com/chsakell/aspnet5-angular2-typescript
I missed the .ToList() at the end of the query.
The full controller know looks like:
[HttpGet(Name = "GetPersonList")]
[ProducesResponseType(typeof(List), 200)]
[SwaggerOperation("GetPersonList")]
public virtual IActionResult GetPersonList()
{
List result = _dbContext.Person
.Include(p => p.MainAdress)
.Select(p => new PersonView()
{
FirstName = p.Firstname,
Lastname = p.Lastname,
Adress = (p.MainAdress == null) ? null :
new AdressView()
{
Street = new Street()
{
Name = p.MainAdress.StreetName,
HouseNumber = p.MainAdress.HouseNumber,
FloorNumber = p.MainAdress.FloorNumber,
DoorNumber = p.MainAdress.DoorNumber
},
City = new City()
{
Name = p.MainAdress.CityName,
PostalCode = p.MainAdress.CityPostalCode
}
}
}
).ToList(); //missed that line
return new ObjectResult(result);
}
I have object like this. This include Group Question (QG), 1 group question has many Question(Q), 1 question has many answer.
public class CrmQuestionAnswer
{
public long QgId { get; set; }
public string QgName { get; set; }
public int QgMIndex { get; set; }
public int QgMdf { get; set; }
public string QgDescription { get; set; }
public long QId { get; set; }
public long QParentId { get; set; }
public string QName { get; set; }
public string QDescription { get; set; }
public int QMindex { get; set; }
public int QMdf { get; set; }
public bool IsMainQuestion { get; set; }
public bool IsTitle { get; set; }
public int QTypeId { get; set; }
public long AnswerId { get; set; }
public string AnswerName { get; set; }
public string AnswerValue { get; set; }
public int AnswerMdf { get; set; }
public int AnswerMIndex { get; set; }
public string AnswerDescription { get; set; }
public long? LinkQuestionId { get; set; }
}
I want to use Linq to map List CrmQuestionAnswer to List QuestionGroupView
public class QuestionGroupView:Title
{
public List<CrmQuestionView> Questions;
}
public class CrmQuestionView: Title
{
public long? ParentId;
public bool? IsMainQuestion;
public bool? IsTitle;
public long? LinkQuestionId;
public List<CrmAnswerView> Answers;
}
public class CrmAnswerView : Title
{
public long? LinkQuestionId;
}
Title is base class:
public class Title
{
public long Id { get; set; }
public string Name { get; set; }
public int MIndex { get; set; }
public int Mdf { get; set; }
public int Type { get; set; }
public string Description { get; set; }
}
I use this code:
public List<QuestionGroupView> GetListQuestionsAnswers(long themaId)
{
var questionAnswerDao = new CrmQuestionAnswerDao();
var questionAnswerlist = questionAnswerDao.GetByThemasId(themaId);
//map List CrmQuestionAnswer -> List QuestionGroupView: 3 level
var listquestiongroup = questionAnswerlist
.OrderBy(t => t.QgMIndex)
.ThenBy(t => t.QMindex)
.GroupBy(t => t.QgId)
.Select(GetQuestionGroup)
.ToList();
return listquestiongroup;
}
private static QuestionGroupView GetQuestionGroup(IGrouping<long, CrmQuestionAnswer> grouping)
{
var group = grouping.First();
var question = new QuestionGroupView
{
Id = group.QgId,
Name = group.QgName,
Description = group.QgDescription,
Mdf = group.QgMdf,
MIndex = group.QgMIndex,
Questions = grouping
.Select(p => new CrmQuestionView
{
Id = p.QId,
Name = p.QName,
Description = p.QDescription,
Mdf = p.QMdf,
MIndex = p.QMindex,
Type = p.QTypeId,
ParentId = p.QParentId,
IsMainQuestion = p.IsMainQuestion,
IsTitle = p.IsTitle,
Answers = grouping//**This line is wrong**
.GroupBy(g => g.QId)
.Select(GetTitle)
.ToList()
})
.ToList()
};
return question;
}
private static CrmAnswerView GetTitle(IGrouping<long, CrmQuestionAnswer> grouping)
{
var group = grouping.First();
var answer = new CrmAnswerView
{
Id = group.AnswerId,
Name = group.AnswerName,
Description = group.AnswerDescription,
MIndex = group.AnswerMIndex,
Mdf = group.AnswerMdf,
Type = group.QTypeId,
LinkQuestionId = group.LinkQuestionId,
};
return answer;
}
This is data get from server Data
My code gets right Group question (2 group) with right List question, but it gets wrong list answer from data.
Can some help me ?
Best regards
i create two class in my model and create relation many to many by Entity
in sql my classes is created tables Properly
when i try to insert data in this table get show error "Object reference not set to an instance of an object." my cod is:
public class News
{
public int ID { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public DateTime Date { get; set; }
public virtual Picture Picture { get; set; }
public virtual NewsType NewsType { get; set; }
public ICollection<Tag> Tag { get; set; }
public News(int id, string title, string content, DateTime date)
{
this.ID = id;
this.Title = title;
this.Content = content;
this.Date = date;
}
public News()
{
}
}
public class Tag
{
public int ID { get; set; }
public string Title { get; set; }
public ICollection<News> News { get; set; }
public Tag()
{
}
}
public class DatabaseContext : DbContext
{
public DatabaseContext()
: base("News")
{
}
static DatabaseContext()
{
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<DatabaseContext>());
}
public DbSet<News> newsInfo { get; set; }
public DbSet<Picture> pictures { get; set; }
public DbSet<NewsType> Types { get; set; }
public DbSet<Tag> Tags { get; set; }
}
[HttpPost]
public ActionResult AddNews(NewsViewModel newsInfo)
{
using (Models.DatabaseContext dbContext = new DatabaseContext())
{
ViewData["Type"] = new SelectList(dbContext.Types.ToList(), "Id", "Title");
}
if (!ModelState.IsValid)
{
return View();
}
else
{
Models.DatabaseContext dbContext = new Models.DatabaseContext();
Models.News news = new Models.News();
news.Title = newsInfo.Title;
news.Content = newsInfo.Content;
news.Date = DateTime.Now;
string newsinput = newsInfo.Tag.cleanTag();
string[] tags = new string[] { };
if (newsinput != null)
{
tags = newsinput.Split(',');
}
foreach (string item in tags)
{
Tag findTag = dbContext.Tags.Where(x => x.Title == item).FirstOrDefault();
if (findTag != null)
{
news.Tag.Add(findTag)
////////////////////////show error in this line
}
}
news.NewsType = dbContext.Types.Find(Convert.ToInt32(Request.Form["rdb"]));
dbContext.newsInfo.Add(news);
dbContext.SaveChanges();
return View();
}
i have a controller action
[HttpPost]
public ActionResult CreateFocus(FocusFormModel focus)
{
var errors = focusService.CanAddFocus(Mapper.Map<FocusFormModel, Focus>(focus)).ToList();
ModelState.AddModelErrors(errors);
if (ModelState.IsValid)
{
focusService.CreateFocus(Mapper.Map<FocusFormModel, Focus>(focus));
var createdfocus = focusService.GetFocus(focus.FocusName);
return RedirectToAction("Focus", new { id = createdfocus.FocusId });
}
return View("CreateFocus", focus);
}
This action is working fine but when i am writing unit test it is showing error
Object Reference Not set to an instance of an object
the uni test is
[Test]
public void Create_Focus()
{
// Arrange
GroupController controller = new GroupController(groupService);
// Act
FocusFormModel focus = new FocusFormModel();
focus.GroupId = 1;
focus.FocusName = "t";
focus.Description = "t";
Mapper.CreateMap<FocusFormModel, Focus>().ForAllMembers(opt => opt.Ignore());
Mapper.AssertConfigurationIsValid();
var result = (RedirectToRouteResult)controller.CreateFocus(focus);
Assert.AreEqual("Index", result.RouteValues["action"]);
}
My Model is described below
public class Focus
{
public int FocusId { get; set; }
[StringLength(50)]
public string FocusName { get; set; }
[StringLength(100)]
public string Description { get; set; }
public int GroupId { get; set; }
public virtual Group Group { get; set; }
public DateTime CreatedDate { get; set; }
public Focus()
{
CreatedDate = DateTime.Now;
}
}
and i am writing my view model as
public class FocusFormModel
{
public int FocusId { get; set; }
[Required(ErrorMessage = "*")]
[StringLength(50)]
public string FocusName { get; set; }
[Required(ErrorMessage = "*")]
[StringLength(100)]
public string Description { get; set; }
public int GroupId { get; set; }
public virtual Group Group { get; set; }
public DateTime CreatedDate { get; set; }
public FocusFormModel()
{
CreatedDate = DateTime.Now;
}
}
Can any one please help me
This line actually provides 2 chances to get null reference exception:
var errors = focusService.CanAddFocus(Mapper.Map<FocusFormModel, Focus>(focus)).ToList();
first of all focusService might be null
if focusService is not null then method call CanAddFocus(Mapper.Map<FocusFormModel, Focus>(focus)) might return null
That are just assumptions.
As Greg Smith said stack trace would be very helpful here.