Catel property is invalid (not serializable?) - entity-framework-6

When I enabled Fody to autogenerate Catel Properties and then run my application, I receive a runtime error saying one of my Properties (which references another entity) is invalid:
Property 'Hedge' is invalid (not serializable?)
This happens in the constructor of my EntityBase, when I try to enable the LeanAndMeanModel flag. The referenced entity is null, which is valid since the hedge property is not required.
Here is the relevant code:
[DataContract]
public class EntityBase : ModelBase, IEntityBase
{
public EntityBase()
{
LeanAndMeanModel = true;
Id = ContextTools.GenerateComb();
}
[Column(Order = 0)]
[Required, Key, DataMember]
public Guid Id { get; set; }
// For Row Level Concurrency
[Column(Order = 2)]
[Timestamp, DataMember]
public Byte[] RowVersion { get; set; }
/// <summary>
/// Called after loading objects using Entity Framework
/// to improve performance and enable proper function
/// of Catel ModelBase features.
///
/// https://catelproject.atlassian.net/wiki/display/CTL/Using+ModelBase+as+base+for+entities
///
/// https://catelproject.atlassian.net/wiki/display/CTL/Performance+considerations
///
/// </summary>
public void PostLoadSetup()
{
IsDirty = false;
LeanAndMeanModel = false;
}
}
[DataContract]
public class TransactionalBase :EntityBase, ITransactionalBase
{
// Convenience field to make querying
// for specific rows easier on the Database Side
[Column(Order = 1), DataMember]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int RowNumber { get; set; }
}
[DataContract]
public class Trade : TransactionalBase, ITrade
{
// Foreign Key
[DataMember]
public Guid? HedgeId { get; set; }
// Navigation Property
[DataMember]
public Hedge Hedge { get; set; }
[DataMember, Required]
public DateTime TradeDate { get; set; }
[DataMember, Required]
public DateTime SettleDate { get; set; }
// More properties follow
// ...
// ...
// ...
}
[DataContract]
public class Hedge : TransactionalBase, IHedge
{
[DataMember, Required]
public DateTime HedgeDate { get; set; }
[DataMember, Required]
public DateTime SettleDate { get; set; }
[DataMember, Required]
public PurchaseType BuySell { get; set; }
// Navigation property
public virtual List<Trade> HedgedTrades { get; set; }
// More properties follow
// ...
// ...
// ...
}

Related

.NET Core 2 Web API: [FromBody] nested object was not binded

I have that post request in my controller:
[HttpPost("subscriptions")]
[Authorize(Policy = Policies.Admin)]
public async Task<IActionResult> PostSubscription([FromBody] PostSubscriptionBindingModel model) { ... }
where PostSubscriptionBindingModel is:
public class PostSubscriptionBindingModel
{
[Required]
public DateTime StartsOn { get; set; }
[Required]
public DateTime ExpiresOn { get; set; }
[Required]
public Gym Gyms { get; set; }
[Required]
public int SubscriptionTypeId { get; set; }
[Required]
public string UserId { get; set; }
public PaymentBindingModel Payment { get; set; }
public class PaymentBindingModel
{
[Required]
public double Amount { get; internal set; }
[Required]
public PaymentType Type { get; internal set; }
[RequiredArray]
public InstalmentBindingModel[] Instalments { get; internal set; }
public class InstalmentBindingModel
{
[Required]
public double Amount { get; internal set; }
public DateTime? ExpiresOn { get; internal set; }
[Required]
public bool IsSetPaid { get; internal set; }
}
}
}
On Angular (v.6) side I've a service with this method:
postSubscription(model: IPostSubscription): Observable<ISubscription> {
return this.http.post<ISubscription>(this.originUrl + '/api/subscriptions', model)
.catch((reason: any) => this.handleError(reason));
}
When I try to post my object to the web api controller, while inside Angular service postSubscription method the model is fully initialized, on web api side only the first level of the object has values. The property Payment (of nested type PaymentBindingModel) is not null but its properties are not initialized, like they are not binded.
How can I solve this problem?
EDIT (added an image)
EDIT 2 (added client code post model)
export interface IPostSubscription {
startsOn: Date;
expiresOn: Date;
gyms: Gym;
subscriptionTypeId: number;
userId: string;
payment?: ISubscriptionPayment;
}
export interface ISubscriptionPayment {
amount: number;
type: PaymentType;
instalments: ISubscriptionPaymentInstalment[];
}
export interface ISubscriptionPaymentInstalment {
amount: number;
expiresOn?: Date;
isSetPaid: boolean;
}
Thank you very much!
In order for model binding to work properly, accessors on the property's get and set should be the default, which is public on public properties. Making the accessor private, internal, or protected will cause the model binding to fail.
Most of the time you will not even get an error; the properties will simply show the default value of the property data type.
The model binder is setting the properties with data from an external source, so they need to be publicly accessible.

Getting Error: "A specified Include path is not valid. The EntityType Field' does not declare a navigation property"

Created method:
public List<Field> GetScheduleDetails()
{
var schedulefields = DBcontextFactory.Context.Set<Field>).Include("ScheduleField").ToList();
}
With the above method i am trying to fetch all joined(field.fieldid=schedulefield.fieldid) records from both tables. The field table is related with schedulefield table. Sorry if i am not familiar with technical terms.
Field Model:
public partial class Field : DOIEntity
{
public Field()
{
this.FilerResponses = new HashSet<FilerResponse>();
this.ScheduleFields = new HashSet<ScheduleField>();
}
public int FieldId { get; set; }
public string FieldDisplayName { get; set; }
public int FieldTypeId { get; set; }
public string HelpText { get; set; }
public Nullable<bool> OtherTextAllowed { get; set; }
public Nullable<int> ChoiceGroupId { get; set; }
public virtual FieldType FieldType { get; set; }
public virtual ICollection<FilerResponse> FilerResponses { get; set; }
public virtual ICollection<ScheduleField> ScheduleFields { get; set; }
}
ScheduleField Model:
public partial class ScheduleField
{
[Key]
public int ScheduleId { get; set; }
public int FieldId { get; set; }
public byte SortOrder { get; set; }
public Nullable<bool> IsMandatory { get; set; }
public Nullable<int> ParentFieldId { get; set; }
public Nullable<int> ParentChoiceId { get; set; }
public virtual Field Field { get; set; }
public virtual Schedule Schedule { get; set; }
}
When I call the method I am getting this error:
A specified Include path is not valid. The EntityType
'WorldBank.DOI.Data.Field' does not declare a navigation property with
the name 'ScheduleField'.
Why am I getting this error?
You have to use the property name of the Field class in the Include string:
public List<Field> GetScheduleDetails()
{
var schedulefields = DBcontextFactory.Context.Set<Field>).Include("ScheduleFields").ToList();
}
This will eager load the ScheduleField objects associated with the Field objects.
Note, you can also eager load many levels. For example, if you want to eager load the schedules of the ScheduleField object as well you would do this:
public List<Field> GetScheduleDetails()
{
var schedulefields = DBcontextFactory.Context.Set<Field>).Include("ScheduleFields.Schedule").ToList();
}

How to design a ViewModel for a todo list application?

I am creating a simple todo application which has two entities, tasks and categories.
To create a task, choosing a category is a must. For this, I figured I would need a ViewModel.
Here is the Task entity
public class Task
{
public int taskId { get; set; }
public int categoryId { get; set; }
public string taskName { get; set; }
public bool isCompleted { get; set; }
public DateTime creationDate { get; set; }
public DateTime completionDate { get; set; }
public string remarks { get; set; }
public string completionRemarks { get; set; }
}
Here is the Category entity
public class Category
{
public int categoryId { get; set; }
public string categoryName { get; set; }
}
How can I design a TaskCategoryViewModel so that I can bind the category in the CreateTask view?
Edit: I am using classic ADO.NET instead of Entity Framework or LINQ to SQL.
Kishor,
the best bet is have model that hods definition for your task and for category (all in one)
here is how everything hangs together.
where
IEnumerable<SelectListItem> Categories
is used for creating drop down list which is ready to use
<%= Html.DropDownListFor(model=>model.NewTask.categoryId, Model.Categories) %>
this will create you nice dropdown list
private IEnumerable<Category> GetCategories
{
get
{
List<Category> categories = new List<Category>
{
new Category() {categoryId = 1, categoryName = "test1"},
new Category() {categoryId = 2, categoryName = "category2"}
};
return categories;
}
}
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult CreateTask()
{
TaskModel taskModel = new TaskModel();
LoadCategoriesForModel(taskModel);
return View(taskModel);
}
private void LoadCategoriesForModel(TaskModel taskModel)
{
taskModel.Categories =
GetCategories.Select(
x =>
new SelectListItem()
{Text = x.categoryName, Value = x.categoryId.ToString(CultureInfo.InvariantCulture)});
}
public ActionResult CreateTask(TaskModel taskModel)
{
if (ModelState.IsValid)
{
// do your logic for saving
return RedirectToAction("Index");
}
else
{
LoadCategoriesForModel(taskModel);
return View(taskModel);
}
}
/// <summary>
/// your model for creation
/// </summary>
public class TaskModel
{
public Task NewTask { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
}
/// <summary>
/// Task
/// </summary>
public class Task
{
public int taskId { get; set; }
public int categoryId { get; set; }
public string taskName { get; set; }
public bool isCompleted { get; set; }
public DateTime creationDate { get; set; }
public DateTime completionDate { get; set; }
public string remarks { get; set; }
public string completionRemarks { get; set; }
}
/// <summary>
/// Category
/// </summary>
public class Category
{
public int categoryId { get; set; }
public string categoryName { get; set; }
}
In the TaskViewModel (I would prefer naming it CreateTaskViewModel) create property for categories select list
public IEnumerable<SelectListItem> CategoriesSelectList;
In controller, bind that property before returning view (note that this also should be done in post handler, when ModelState is invalid)
public ViewResult Create()
{
CreateTaskViewModel model = new CreateTaskViewModel();
model.CategoriesSelectList = _repository.AllCategories().Select(x=> new SelectListItem(){ Text = x.CategoryName, Value = x.CategoryId.ToString();}
}
And finally, in the view
Html.DropDownListFor(model => model.CategoryId, Model.CategoriesSelectList)
Edit:
In your code, _repository.AllCategories() should be replaced by your data access code, that returns object having type IEnumerable<Category>. It actually does not matter which data access technology you use. And do not forget to add the using System.Linq; statement to your controller file, if it's missing.

EntityType 'ApplicantPosition' has no key defined

When running my first asp.net mvc application I got this error
I thought that entity framework automatically would create the keys of column names that end with Id? isnt it correct?
As you can see the ApplicantPositionID would be a table with 2 columns as primary key because it would relate to Applicants and also to Position.
One or more validation errors were detected during model generation:
System.Data.Edm.EdmEntityType: : EntityType 'ApplicantImage' has no key defined. Define the key for this EntityType.
System.Data.Edm.EdmEntityType: : EntityType 'ApplicationPositionHistory' has no key defined. Define the key for this EntityType.
System.Data.Edm.EdmEntitySet: EntityType: EntitySet �ApplicantsPositions� is based on type �ApplicantPosition� that has no keys defined.
System.Data.Edm.EdmEntitySet: EntityType: EntitySet �ApplicantImages� is based on type �ApplicantImage� that has no keys defined.
System.Data.Edm.EdmEntitySet: EntityType: EntitySet �ApplicationsPositionHistory� is based on type �ApplicationPositionHistory� that has no keys defined.
The error is thrown in this line:
public ActionResult Index()
{
return View(db.Positions.ToList());
}
And my model is the following one:
namespace HRRazorForms.Models
{
public class Position
{
public int PositionID { get; set; }
[StringLength(20, MinimumLength=3)]
public string name { get; set; }
public int yearsExperienceRequired { get; set; }
public virtual ICollection<ApplicantPosition> applicantPosition { get; set; }
}
public class Applicant
{
public int ApplicantId { get; set; }
[StringLength(20, MinimumLength = 3)]
public string name { get; set; }
public string telephone { get; set; }
public string skypeuser { get; set; }
public ApplicantImage photo { get; set; }
public virtual ICollection<ApplicantPosition> applicantPosition { get; set; }
}
public class ApplicantPosition
{
public int ApplicantID { get; set; }
public int PositionID { get; set; }
public virtual Position Position { get; set; }
public virtual Applicant Applicant { get; set; }
public DateTime appliedDate { get; set; }
public int StatusValue { get; set; }
public Status Status
{
get { return (Status)StatusValue; }
set { StatusValue = (int)value; }
}
//[NotMapped]
//public int numberOfApplicantsApplied
//{
// get
// {
// int query =
// (from ap in Position
// where ap.Status == (int)Status.Applied
// select ap
// ).Count();
// return query;
// }
//}
}
public class ApplicantImage
{
public int ApplicantId { get; private set; }
public byte[] Image { get; set; }
}
public class Address
{
[StringLength(20, MinimumLength = 3)]
public string Country { get; set; }
[StringLength(20, MinimumLength = 3)]
public string City { get; set; }
[StringLength(20, MinimumLength = 3)]
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
}
public class ApplicationPositionHistory
{
public ApplicantPosition applicantPosition { get; set; }
public Status oldStatus { get; set; }
public Status newStatus { get; set; }
[StringLength(500, MinimumLength = 10)]
public string comments { get; set; }
public DateTime dateModified { get; set; }
}
public enum Status
{
Applied,
AcceptedByHR,
AcceptedByTechnicalDepartment,
InterviewedByHR,
InterviewedByTechnicalDepartment,
InterviewedByGeneralManager,
AcceptedByGeneralManager,
NotAccepted
}
}
EF Code First can only infer that a property is a primary key if the property is called Id or <class name>Id (or if it is annotated with the Key attribute).
So you need to extend your e.g. ApplicantImage with an ApplicantImageId or Id property etc.
Edit: An artice about the coneventions: Conventions for Code First
You can add the [Key] atributte to the property ApplicantId or do it via Fluent API overriding OnModelCreating method DbContext
modelBuilder.Entity<ApplicantImage >().HasKey(p => p.ApplicantId);
In your case, EF naming convention first looks for an ID (case-insensitive) column. If nothing, looks for ApplicantImageId and when it founds nothing, it raises that error.
So, you should add the [Key] attribute on your ID:
public class ApplicantImage
{
[Key]
public int ApplicantId { get; private set; }
public byte[] Image { get; set; }
}
and if ApplicantId column is identity in your database, you should add another attribute too:
public class ApplicantImage
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ApplicantId { get; private set; }
public byte[] Image { get; set; }
}
I know this is an old question but it is still relevant. I ran into the same situation however we use a .tt file to generate the .cs from our edmx. Our .tt is setup to add the [Key] attribute on our first column of the table for most situations, but in my case i was using a row over () in SQL to generate unique id's for the first column (works great for most situations). The problem with that was it makes a nullable and the .tt wasn't setup to add [Key] in this case.
Wrapping the row Over() in a ISNULL ((),0) was able to fix making the column not null and solved my problem. Otherwise, as mentioned by marianosz, simply using the .HasKey() in your data context will work fine too.

How to make a nullable property in EF Codefirst?

I have two POCOs in my "Bookshelf" test application:
/// <summary>
/// Represents a book
/// </summary>
public class Book
{
public int ID { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public string ISBN { get; set; }
public virtual Loaner LoanedTo { get; set; }
}
/// <summary>
/// Represents a Loaner
/// </summary>
public class Loaner
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Book> Loans { get; set; }
}
Is there a way that my LoanedTo could be nullable? I mean a book isn't always loaned, right! I tried
public virtual Loaner? LoanedTo { get; set; }
But I get:
The type 'RebtelTests.Models.Loaner' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Nullable'
So I must be thinking wrong somewhere, but I can't figure it out. Probably easy squeeze for you guys.
You don't need to do anything special. Classes are always nullable.
I just tried this (with MVC3):
In my Models directory:
namespace MvcApplication2.Models
{
public class Book
{
public int ID { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public string ISBN { get; set; }
public virtual Loaner LoanedTo { get; set; }
}
public class Loaner
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Book> Loans { get; set; }
}
public class BookContext : System.Data.Entity.DbContext
{
public System.Data.Entity.DbSet<Book> Books { get; set; }
public System.Data.Entity.DbSet<Loaner> Loaners { get; set; }
}
}
In my HomeController:
namespace MvcApplication2.Controllers
{
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
string message = "OK";
try
{
var context = new Models.BookContext();
var book = new Models.Book();
book.Title = "New Title";
book.Author = "New Author";
book.ISBN = "New ISBN";
context.Books.Add(book);
context.SaveChanges();
}
catch (Exception err)
{
message = err.ToString();
}
ViewBag.Message = message;
return View();
}
}
}
The connectionstring in Web.Config:
<add name="BookContext" connectionString="Data Source=|DataDirectory|BookContext.sdf" providerName="System.Data.SqlServerCe.4.0" />
When I run the application, the view displays "OK". This means that no exception was thrown. When I look in my App_Data folder, a BookContext.sdf file has been created. That database contains a table for the Books and the Loaners. The table for the Loaners is empty. The one for the Books contains one record:
ID: 1; Title: "New Title"; Author: "New Author"; ISBN: "New ISBN"; LoanerID: null
If you are talking about a simple property like int, bool, or float use int?, bool?, or float?
like
public int? ID { get; set; }
public bool? Exists { get; set; }
Couldn't you just use something like this
public virtual Nullable<Loaner> LoanedTo { get; set; }
That then should make LoanedTo a nullable property

Resources