Getting generated value from Identity Column in EF Core 7 - asp.net-web-api

I still get zero as response on my Edentity Column after SaveChangesAsync().
Here's my entity
public class Person
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int PersonID { get; set; }
[Required, Column(TypeName = "VARCHAR"), StringLength(50)]
public string? Name { get; set; }
[Required, Column(TypeName = "VARCHAR"), StringLength(50), DataType(DataType.EmailAddress)]
public string? Email { get; set; }
public DateTime DateOfBirth { get; set; }
[StringLength(100)]
public string? Address { get; set; }
}
public static class PersonExtensionMethod
{
public static PersonResponse ToResponse(this Person person)
{
return new PersonResponse()
{
PersonID = person.PersonID,
Name = person.Name,
Email = person.Email,
DateOfBirth = person.DateOfBirth,
Address = person.Address,
};
}
}
Here's my insert method from service
public Task<PersonResponse?> AddPersonAsync(PersonAddRequest addRequest)
{
Person newPerson = addRequest.ToPerson();
_dbContext.Persons.Add(newPerson);
_dbContext.SaveChangesAsync();
return Task.FromResult<PersonResponse?>(newPerson.ToResponse());
}
But I Still Get 0 as PersonID on response

You have missed await and insert into database performed later than response has been generated:
public async Task<PersonResponse?> AddPersonAsync(PersonAddRequest addRequest)
{
Person newPerson = addRequest.ToPerson();
_dbContext.Persons.Add(newPerson);
await _dbContext.SaveChangesAsync();
return newPerson.ToResponse();
}

Related

automapper issue in nested entity

Entity:
public class AccountEntity: MasterEntity
{
public AccountType AccountType { get; set; }
public DepartmentEntity Department { get; set; }
public string LeadSource { get; set; }
public ResourceEntity AccountManager { get; set; }
public AccountQualificationStatus QualificationStatus { get; set; }
}
public class DepartmentEntity : MasterEntity
{
}
public class ResourceEntity : MasterEntity
{
public string Email { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
}
public abstract class MasterEntity: Entity
{
public string Name { get; set; }
public string Code { get; set; }
}
Model
public class Accounts
{
private string depname;
public int Id { get; set; }
public string Name { get; set; }
public int Code { get; set; }
public string AccountType { get; set; }
public string Department { get; set; }
}
public AccountMappingProfile()
{
CreateMap<Account, AccountTest>().ReverseMap();
CreateMap<Opportunity, OpportunityEntity>().ReverseMap();
CreateMap<Accounts, AccountEntity>().ReverseMap();
CreateMap<Resource, ResourceEntity>().ReverseMap();
CreateMap<Projects, ProjectEntity>().ReverseMap();
}
public static class AccountMapper
{
private static readonly Lazy<IMapper> Lazy = new Lazy<IMapper>(() =>
{
var config = new MapperConfiguration(cfg => {
cfg.ShouldMapProperty = p => p.GetMethod.IsPublic || p.GetMethod.IsAssembly;
cfg.AddProfile<AccountMappingProfile>();
});
var mapper = config.CreateMapper();
return mapper;
});
public static IMapper Mapper => Lazy.Value;
}
I am able to fetch resource details .while I am fetching accounts with department and resources, the value for department is giving me null after automapping.
public async Task<IEnumerable<Accounts>> GetAccounts()
{
try
{
var accounts = await _context.Account.Include(c=>c.Director).ToListAsync();
// accounts = await _context.Account.Include(c => c.Department).ToListAsync();
return AccountMapper.Mapper.Map<List<Accounts>>(accounts);
}
}
controller method:
public async Task<IEnumerable<Accounts>> GetClients()
{
var result = await _repository.GetAccounts();
return result;
}
if I am uncommenting the code to include department, its is giving the object name.
I need to get the department details as well. how can i get that.Department entity is inheriting master entity.

Fluent LINQ EF Core - Select filtered child property

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
});

Convert collections of database entities to collections of view models

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);
}

Select Foreign key data in EF

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();

Object reference error in unit testing

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.

Resources