The following constructors had parameters that could not be bound to properties of the entity type: - asp.net

Im trying to create a constructor for the trail model. I need the constructor because Im modyfing the controller, this is the actual implementation of the controller (I don't think the problem is there):
public async Task<ActionResult<Trail>> PostTrail(
string Name, int CreatorId, Difficulty difficulty, string Description)
{
if (_context.Trails == null)
{
return Problem("Entity set 'LivetrailsDBContext.Trails' is null.");
}
if (_context.Trails.Any(trail => trail.Name == Name))
{
return Problem($"Trail with name {Name} already exists ");
}
var creator = _context.Users.Find(CreatorId);
if (creator == null)
{
Problem($"There is no creator with such Id ({CreatorId})");
}
Trail trail = new Trail(Name, creator, difficulty, Description);
_context.Trails.Add(trail);
await _context.SaveChangesAsync();
return CreatedAtAction("GetTrail", new { id = trail.Id }, trail);
}
So, I created the suitable constructor, but when I run add-migration it returns this error:
No suitable constructor was found for entity type 'Trail'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'creator' in 'Trail(string name, User creator, Difficulty difficulty, string description)'.
Here is the Trail class with the constructor:
namespace LivetrailsBackend.Models.DataModels
{
public class Trail: BaseEntity
{
[Required, StringLength(50)]
public string Name { get; set; }
[Required]
public User Creator { get; set; }
[Required]
public int CreatorId { get; set; }
[Required]
public Difficulty Difficulty { get; set; }
public string Description { get; set; }
public Trail(string name, User creator, Difficulty difficulty, string description)
{
Name = name;
Creator = creator;
CreatorId = creator.;
Difficulty = difficulty;
Description = description;
}
}
}
Here is the User model:
namespace LivetrailsBackend.Models.DataModels
{
public class User: BaseEntity
{
[Required, StringLength(20)]
public string UserName { get; set; }
[Required, EmailAddress]
public string Email { get; set; }
[Required]
public string Password { get; set; }
public ICollection<Trail> Trails { get; set; } = new List<Trail>();
}
}

you have a bug in your code. when creator == null the code should return error
if (creator == null)
{
Problem($"There is no creator with such Id ({CreatorId})");
return .... your error code
}
and IMHO instead of creator it is much better to use just a creatorId, you don't need to assign both, fix your constructor too
[Required]
public int CreatorId { get; set; }
public User Creator { get; set; }

Related

Deserialize JSON into List with X++

I have a problem with generic types in X++. I need to deserialize a JSON list yet everything I tried failed. Like using IEnumerables and JsonSerializer(does it find only AX classes and can't see references library classes?).
My helper class is in a C# library and I only need to get access to values inside the response JSON that are in list. How can I archive this in X++?
//X++
defaultException defaultException= new defaultException();
defaultException= JsonConvert::DeserializeObject(response, defaultException.GetType()); <- this gives is correct yet I cant use the values in the list
//values = FormJsonSerializer::deserializeCollection(classnum(List), response, Types::Class, 'defaultException');
// C#
public class defaultException
{
public MyException exception { get; set; }
}
public class MyException
{
public string serviceCtx { get; set; }
public string serviceCode { get; set; }
public string serviceName { get; set; }
public string timestamp { get; set;}
public string referenceNumber { get; set; }
public List<exceptionDetailList> exceptionDetailList { get; set; }
}
public class exceptionDetailList
{
public int exceptionCode { get; set; }
public string exceptionDescription { get; set; }
}
Found a solution. If we have another list in this list we need to recreate the enumerator in loop again and again as needed.
defaultException defaultException = new defaultException();
defaultException = JsonConvert::DeserializeObject(batch, defaultException.GetType());
System.Collections.IEnumerable exceptionList = defaultException.exception.exceptionDetailList;
System.Collections.IEnumerator enumerator = exceptionList.GetEnumerator();
while (enumerator.MoveNext())
{
exceptionDetailList exceptionDetailList = new exceptionDetailList();
exceptionDetailList = enumerator.Current;
}

How skip NullReferenceException in Get API

Here create an API to get the records, in my entity relation table there are twice start date and end date. Here my compulsion is one of them need to keep Null able type.
Here is ER that is SchoolCourses:
public class SchoolCourses
{
public Guid ID { get; set; }
public DateTime StartCourseDate { get; set; }
public DateTime EndCourseDate { get; set; }
public DateTime? StartSemDate { get; set; } // Null able type
public DateTime? EndSemDate { get; set; } // Null able type
}
I creates a repository for getting the value:
public async Task<ICollection<SchoolCourses>> GetcourseBySchoolId(Guid SchoolId)
{
List<SchoolCourses> schoolCourses = null;
schoolCourses = await _GpsContext.SchoolCourses.AsNoTracking()
.Where(x => x.SchoolsID == SchoolId)
.ToListAsync();
return schoolCourses;
}
And the Controller are like this:
public async Task<IActionResult> GetforSchoolCourse(string SchoolId)
{
var result = await _schoolCoursesRepository.GetcourseBySchoolId(Guid.Parse(SchoolId));
List<GetSchoolCourseBySchoolIdVm> getSchoolCourseBySchoolIdVms = new List<GetSchoolCourseBySchoolIdVm>();
foreach (SchoolCourses schoolCourse in result)
{
getSchoolCourseBySchoolIdVms.Add(new GetSchoolCourseBySchoolIdVm
{
id = schoolCourse.ID.ToString(),
StarCoursetDate = schoolCourse.StartCourseDate.ToString(),
EndCourseDate = schoolCourse.EndCourseDate.ToString(),
StartSemDate = schoolCourse.StartSemDate.ToString(),
EndSemDate = schoolCourse.EndSemDate.ToString(),
});
}
return Ok(getSchoolCourseBySchoolIdVms);
}
Here is View Model for reference:
public class GetSchoolCourseBySchoolIdVm
{
public string id { get; set; }
public string StarCoursetDate { get; set; }
public string EndCourseDate { get; set; }
public string StartSemDate { get; set; }
public string EndSemDate { get; set; }
}
After doing all the above staff it is getting exception error in swagger is following:
System.NullReferenceException: Object reference not set to an instance of an object.;
In your SchoolCourses model StartSemDate and EndSemDate are nullable types, so it must be possible that values of those fields are null. That should have been checked before using it, unlike you have used
StartSemDate = schoolCourse.StartSemDate.ToString(),
EndSemDate = schoolCourse.EndSemDate.ToString(),
here if any of the date is null then calling .ToString() method on it will throw NullReferenceException. Use safe navigation operator to check
schoolCourse.StartSemDate?.ToString()
or
schoolCourse.StartSemDate != null ? schoolCourse.StartSemDate.ToString() : string.Empty

Clean way for updating object in a collection of abstract objects

As I'm developping an asp net core + ef core 2.0 with localized objects in my model, I adapted the solution provided in the following link to localize my objects link.
I'm now trying to find a clean way to update my collection of translation when updated object are received in the controller.
For the moment I have a step model class defined this way :
public class Step
{
//Native properties
public Guid ID { get; set; }
public string Name { get; set; }
public int Order { get; set; }
public string ScriptBlock { get; set; }
//Parent Step Navigation property
public Nullable<Guid> ParentStepID { get; set; }
public virtual Step ParentStep { get; set; }
//Collection of sub steps
public virtual ICollection<Step> SubSteps { get; set; }
//MUI Properties
public TranslationCollection<StepTranslation> Translations { get; set; }
public string Description { get; set; }
//{
// get { return Translations[CultureInfo.CurrentCulture].Description; }
// set { Translations[CultureInfo.CurrentCulture].Description = value; }
//}
public Step()
{
//ID = Guid.NewGuid();
Translations = new TranslationCollection<StepTranslation>();
}
}
public class StepTranslation : Translation<StepTranslation>
{
public Guid StepTranslationId { get; set; }
public string Description { get; set; }
public StepTranslation()
{
StepTranslationId = Guid.NewGuid();
}
}
Translation and translationCollection are the same as in the link
public class TranslationCollection<T> : Collection<T> where T : Translation<T>, new()
{
public T this[CultureInfo culture]
{
// indexer
}
public T this[string culture]
{
//indexer
}
public bool HasCulture(string culture)
{
return this.Any(x => x.CultureName == culture);
}
public bool HasCulture(CultureInfo culture)
{
return this.Any(x => x.CultureName == culture.Name);
}
}
public abstract class Translation<T> where T : Translation<T>, new()
{
public Guid Id { get; set; }
public string CultureName { get; set; }
protected Translation()
{
Id = Guid.NewGuid();
}
public bool HasProperty(string name)
{
return this.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Any(p => p.Name == name);
}
}
My issue in this sample is how to deal correctly with the PUT method and the Description property of my step controller. When it receive a Step object to update (which is done through a native c# client) only the string Description property of Step might have been created/updated/unchanged. So I have to update/create/do Nothing on the Description of the translation in the correct culture.
My first guess is to add in the TranslationCollection class a method in which I could pass the culture, the name of the property to update or not (Description in this case) and the value of the Description.
But as the TranslationCollection is a collection of abstract objects I don't even if this is a good idea and if it's possible.
If someone would have any advice on it (hoping I was clear enough) it would be great !
Finally answered my own question, and it was quite simple.
Just had to use the indexer like :
myobject.Translations[userLang].Name = value;

Created and Modified date issue

I was practicing User.Identity and timestamps functions in ASP.NET MVC 5,
So I created a student class filled some properties, I just wanted to test if it is capturing timestamps and userId, so user id is getting captured and datetime too, problem is whenever I'm editing a record and save it, its created date becomes Null and modified date is updated, please review the code and help.
Thanks in advance.
Below is the Code
{
public class BaseEntity
{
public DateTime? DateCreated { get; set; }
public string UserCreated { get; set; }
public DateTime? DateModified { get; set; }
public string UserModified { get; set; }
}
public class Student : BaseEntity
{
public int Id { get; set; }
public string Name { get; set; }
public string Subject { get; set; }
public string Class { get; set; }
public Section Section { get; set; }
public byte SectionId { get; set; }
}
then I used Codefirst approach and created an application Database and added this code in Identity Model
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public DbSet<Student> Students { get; set; }
public override int SaveChanges()
{
AddTimestamps();
return base.SaveChanges();
}
//public override async Task<int> SaveChangesAsync()
//{
// AddTimestamps();
// return await base.SaveChangesAsync();
//}
private void AddTimestamps()
{
var entities = ChangeTracker.Entries().Where(x => x.Entity is BaseEntity && (x.State == EntityState.Added || x.State == EntityState.Modified));
var currentUsername = !string.IsNullOrEmpty(System.Web.HttpContext.Current?.User?.Identity?.Name)
? HttpContext.Current.User.Identity.Name
: "Anonymous";
foreach (var entity in entities)
{
if (entity.State == EntityState.Added)
{
((BaseEntity)entity.Entity).DateCreated = DateTime.UtcNow;
((BaseEntity)entity.Entity).UserCreated = currentUsername;
}
else
((BaseEntity)entity.Entity).DateModified = DateTime.UtcNow;
((BaseEntity)entity.Entity).UserModified = currentUsername;
}
}
public DbSet<Section> Sections { get; set; }
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false)
{
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
}
I have created a simple controller with create,edit and dispay actions.
The code you posted doesn't show DateCreated being set to null as far as I can see. I think the issue is when you save an existing record you do not have the DateCreated or UserCreated fields in your view. So when you post the form the MVC model binder doesn't see them and thus sets them to null (I'm assuming your are binding to the Student model in your controller action).
In your edit view add the following hidden fields:
#Html.HiddenFor(model => model.DateCreated)
#Html.HiddenFor(model => model.UserCreated)
Now when you post the form the MVC model binder will bind these values to your model and save them to the database.

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