I'm trying to new
ICollections in my derived classes - should this be done in the object constructor or/and when I'm creating a new instance of an object in my Register ActionResult()
?
Tenant inherits from UserProfile - simplified example:
public class Tenant : UserProfile
{
public Tenant()
{
this.ReferencePhotos = new List<ReferencePhoto>();
// ReferencePhoto extends Image
}
// A Tenant can have many ReferencePhotos
[ForeignKey("ImageId")] // Id of parent class
public virtual ICollection<ReferencePhoto> ReferencePhotos { get; set; }
}
I've tried to do the above but it results in an InvalidCastException:
Unable to cast object of type 'System.Collections.Generic.List'1[Namespace.Models.ReferencePhoto]' to type [Namespace.Models.ReferencePhoto]'.
Why is it trying cast from one object to another when they're the same?
In my Register ActionResult()
I've also tried this (with and without setting ICollections in object contructor):
public ActionResult Register(RegisterModel model)
{
using (var db = new LetLordContext())
{
var tenant = db.UserProfile.Create<Tenant>();
tenant.ReferencePhotos = new List<ReferencePhoto>();
// Do I need to new it here at all/as well?
db.UserProfile.Add(tenant); // Exception being thrown here
db.SaveChanges();
Roles.AddUserToRole(model.UserName, "Tenant");
WebSecurity.Login(model.UserName, model.Password);
return RedirectToAction("Confirm", "Home", tenant);
}
}
The above also throws the same exception mentioned earlier. Can anyone offer any insight?
EDIT: Added UserProfile code
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.None)]
public int UserId { get; set; }
[Display(Name = "Username")]
[Required(ErrorMessage="Username is required.")]
public string UserName { get; set; }
[Display(Name = "First name")]
[Required(ErrorMessage = "First name is required.")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Account type is required.")]
public AccountType AccountType;
public virtual string AccountTypeString
{
get { return AccountType.ToString(); }
set
{
AccountType newValue;
if (Enum.TryParse(value, out newValue))
{ AccountType = newValue; }
}
}
}
EDIT: Added context code and ReferencePhoto code
public class LetLordContext : DbContext
{
public DbSet<LetLord.Models.UserProfile> UserProfile { get; set; } // 1 DbSet for superclass UserProfile
public DbSet<LetLord.Models.Image> Image { get; set; } // 1 DbSet for superclass Image
public DbSet<LetLord.Models.ResidentialProperty> ResidentialProperty { get; set; }
public DbSet<LetLord.Models.TenantGroupMember> TenantGroupMember { get; set; }
public DbSet<LetLord.Models.Viewing> Viewing { get; set; }
public DbSet<LetLord.Models.TenantPreferences> TenantPreferences { get; set; }
public DbSet<LetLord.Models.LandlordPreferences> LandlordPreferences { get; set; }
public DbSet<LetLord.Models.Address> Address { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
I'm using table-per-type inheritance hence only DbSet
s for base classes are implemented.
public class ReferencePhoto : Image
{
// 1:many with Tenant
public int UserId { get; set; }
[ForeignKey("UserId")]
public virtual Tenant Tenant { get; set; }
}
I can workaround this issue by not initialising the list in the object constructor or when creating a new entity. To achieve this I use a null coalescing operator in the GET ActionResult
that returns a Tenant
object in a partial view. In the partial, I check if Model.ReferencePhotos == null
. If it is, a user can upload a photo. When a photo is uploaded, it is added to the list, I can confirm this by checking the database. However, when I login again, the if
in the partial view mentioned previously throws the following exception:
Unable to set field/property ReferencePhotos on type System.Data.Entity.DynamicProxies.Tenant_...
with an inner exception:
Unable to cast object of type 'System.Data.Entity.DynamicProxies.ReferencePhoto_3DFB9F64061D55E5AF6718A74C97025F77EFB2BB9C2A6E43F5A6AF62A6A73E75' to type 'System.Collections.Generic.ICollection`1[LetLord.Models.ReferencePhoto]'."}
This may provide more insight.