EF: TPH implementation with Fluent mapping throws Invalid Column Name exception - entity-framework-4.1

Here is my implementation.
public partial class Person
{
#region Constructors
public Person()
{
PersonExpirableCredentials = new List<personexpirablecredential>();
}
#endregion Constructors
#region Properties
public int PersonID
{
get;
protected set;
}
public virtual ICollection<personexpirablecredential> PersonExpirableCredentials
{
get;
set;
}
#endregion
}
public abstract class PersonCredential
{
#region Constructors
public PersonCredential()
{
}
#endregion
#region Properties
public int PersonID
{
get;
protected set;
}
public int PersonCredentialID
{
get;
protected set;
}
public System.DateTime WhenEffective
{
get;
set;
}
public Nullable<system.datetime> WhenExpire
{
get;
set;
}
public virtual Person Person
{
get;
set;
}
}
public partial class PersonExpirableCredential : PersonCredential
{
#region Constructors
public PersonExpirableCredential() :
base()
{
}
#endregion
#region Properties
public DateTime? WhenCompleted
{
get;
set;
}
public string CredentialNumber
{
get;
set;
}
#endregion
}
Below are the fluent mappings
internal partial class PersonMapping : EntityTypeConfiguration<person>
{
#region Constructors
public PersonMapping()
{
this.HasKey(t => t.PersonID);
this.ToTable("Person");
}
#endregion
}
internal partial class PersonCredentialMapping : EntityTypeConfiguration<personcredential>
{
#region Constructors
public PersonCredentialMapping()
{
this.HasKey(t => new { t.PersonCredentialID });
this.ToTable("PersonCredential");
this.HasRequired(t => t.Person).WithMany().HasForeignKey(d => d.PersonID);
}
#endregion
}
internal partial class PersonExpirableCredentialMapping : EntityTypeConfiguration<personexpirablecredential>
{
#region Constructors
public PersonExpirableCredentialMapping()
{
this.Map(m =>
{
m.Requires("CredentialCategoryCode").HasValue("Expirable");
});
this.ToTable("PersonCredential");
}
#endregion
}
Here is the database model:
Now in my data access layer, when i retrieve the person and try to do access "Person.PersonExpirableCredentials". It throws an error with Invalid Column Name "Person_PersonID". Below is the SQL query, it generates.
exec sp_executesql N'SELECT
[Extent1].[PersonID] AS [PersonID],
''1X0X'' AS [C1],
[Extent1].[PersonCredentialID] AS [PersonCredentialID],
[Extent1].[WhenEffective] AS [WhenEffective],
[Extent1].[WhenExpire] AS [WhenExpire],
[Extent1].[WhenCompleted] AS [WhenCompleted],
[Extent1].[CredentialNumber] AS [CredentialNumber],
[Extent1].[Person_PersonID] AS [Person_PersonID]
FROM [dbo].[PersonCredential] AS [Extent1]
WHERE ([Extent1].[Person_PersonID] IS NOT NULL) AND ([Extent1].[Person_PersonID] = #EntityKeyValue1) AND ([Extent1].[CredentialCategoryCode] = ''Expirable'')',N'#EntityKeyValue1 int',#EntityKeyValue1=3
For some reason, EF is not able to identify the relationship between the Person Class and the subclass PersonExpirableCredentials.
Help Please.
Thanks

Try this
this.HasRequired(t => t.Person).WithMany(p => p.PersonExpirableCredentials).HasForeignKey(d => d.PersonID);
Modify your collection to be of base type
public virtual ICollection<PersonCredential> PersonExpirableCredentials
{
get;
set;
}

You must set both getter and setter of the PersonID to public.
public int PersonID
{
get;
set;
}
There are several places you have set the setter protected. Change those to public as well.

Related

How to send enum property in a json to .net core 3.1 API?

Everything looks good but I don't understand why I still get an error like:
"System.InvalidCastException: The field of type DotnetCoreWebAPI.Enum+Blood must be a string, array or ICollection type."
I've left some meaningful snippets of code and the error I'm getting, below.
Model:
public class User
{
[Key]
public int Id { get; set; }
[Required]
[MaxLength(100)]
public string Name { get; set; }
[MaxLength(100)]
public string Surname { get; set; }
[MaxLength(2)]
public Enum.Blood Blood { get; set; }
[MaxLength(50)]
public string Cellphone { get; set; }
[MaxLength(500)]
public string Adress { get; set; }
}
Enum:
public class Enum
{
public enum Blood
{
ARhDpositive,
ARhDnegative,
BRhDpositive,
BRhDnegative,
ORhDpositive,
ORhDnegative,
ABRhDpositive,
ABRhDnegative
}
}
Controller:
[HttpPost]
public ActionResult<UserReadDto> CreateUser(User userCreateDto)
{
var userModel = _mapper.Map<User>(userCreateDto);
_repository.CreateUser(userModel);
return Ok(userModel);
}
Service Configurations:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<UserContext>(opt => opt.UseSqlServer
(Configuration.GetConnectionString("DatabaseConnection")));
services.AddControllers().AddJsonOptions(opt =>
opt.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));
services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
services.AddScoped<IUserRepo, SqlUserRepo>();
}
Note:
I use Postman when I test api
I found out why problem occurs, I've wrote User instead of UserCreateDto in this line:
public ActionResult<UserReadDto> CreateUser(**UserCreateDto ** userCreateDto)

How to set nullable foreign reference in asp.net mvc code first method?

In my project there is one to may relationship with two table(questions and asnwars). but when creating question no need to add answar but in my problem getting this error
Object reference not set to an instance of an object.
how can I solve this? is there any wrong thing in my code
this is the code what I tried.
public class QuestionDTO
{
[Key]
public int Id { get; set; }
public string Title { get; set; }
public string question { get; set; }
public int votes { get; set; }
public ApplicationUser starter { get; set; }
public virtual ICollection<VegCategoryDTO> tags { get; set; }
public ICollection<AnswerDTO> answers { get; set; }
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<QuestionDTO>().ToTable("tblQuestion");
modelBuilder.Entity<AnswerDTO>()
.HasRequired<QuestionDTO>(s => s.Question)
.WithMany(g => g.answers)
.HasForeignKey<int>(s => s.QuestionId)
.WillCascadeOnDelete();
}
}
public class QuestionController : ApiController
{
[AllowAnonymous]
public QuestionVM Post(QuestionVM model)
{
//if (!ModelState.IsValid)
//{
// return null;
//}
QuestionDTO dto = new QuestionDTO();
using (Db db = new Db())
{
dto.Id = model.Id;
dto.Title = model.Title;
dto.votes = model.votes;
dto.question = model.question;
ApplicationUser currentUser = (new ApplicationDbContext()).Users.FirstOrDefault(x => x.Id == userId);
dto.starter = currentUser;
dto.tags = model.tags;
dto.answers = model.answers;
db.Questions.Add(dto);
db.SaveChanges();
}
//_DbContext.SaveChanges();
return new QuestionVM(dto);
}
}
public class Db : DbContext
{
public DbSet<VegCategoryDTO> VegCategories { get; set; }
public DbSet<QuestionDTO> Questions { get; set; }
public DbSet<AnswerDTO> Answers { get; set; }
public DbSet<ApplicationUser> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<QuestionDTO>()
.HasMany<VegCategoryDTO>(s => s.tags)
.WithMany(c => c.Questions)
.Map(cs =>
{
cs.MapLeftKey("QuestiontRefId");
cs.MapRightKey("VegCategoryRefId");
cs.ToTable("QuestiontVegCategory");
});
modelBuilder.Entity<AnswerDTO>()
.HasRequired<QuestionDTO>(s => s.Question)
.WithMany(g => g.answers)
.HasForeignKey<int>(s => s.QuestionId)
.WillCascadeOnDelete();
}
}

How to add to a collection in Entity Framework 4.1

I'm trying to add an object to an IList entity but the runtime throws a 'Object reference not set to an instance of an object.' exception.
Here is my model:
public class Discussion
{
[Key]
public int DiscussionId { get; set; }
public string Title { get; set; }
public virtual List<Message> Messages { get; set; }
public virtual List<Tag> Tags { get; set; }
public Guid Guid { get; set; }
public string UrlTitle { get; set; }
}
and here is the problematic line:
newDiscussion.Messages.Add(newMessage);
Apparently newDiscussion.Messages is null. What am I doing wrong?
Mark
You should initialize any collections inside of the class's constructor.
public class Discussion
{
public Discussion()
{
Messages = new List<Message>();
Tags = new List<Tag>();
}
// ...
}

Web Api won't serialize my Object Graph

I got two simple entities:
public class Ingredient : IEntity
{
public Ingredient()
{
Drinks = new List<Drink>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Drink> Drinks { get; set; }
}
public class Drink : IEntity
{
public Drink()
{
Ingridients = new List<Ingredient>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Ingredient> Ingridients { get; set; }
public string Approach { get; set; }
}
I get the following error:
Object graph for type 'Gudo.Core.Model.Ingredient' contains cycles and cannot be serialized if reference tracking is disabled.
I've tried using the JsonIgnore Attribute on the Drinks collection and I've tried using:
JsonSerializerSettings jsSettings = new JsonSerializerSettings();
jsSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
In my global.asax
Nothing works..
Please help.
Did you make sure to set this on the JSON formatter's serializer settings? This line should do it for you:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;

Override FluentNHibernate Auto mapping

I need change for the next class data type assumed by default FluentNHibernate Automapping
public class plaparte
{
public virtual int id { get; private set; }
public virtual int vivos { get; set; }
public virtual int lesionados { get; set; }
public virtual int quemados { get; set; }
public virtual int muertos { get; set; }
public virtual int otros { get; set; }
public virtual string colaboracion { get; set; }
public virtual decimal hectareas { get; set; }
public virtual string reconocimiento { get; set; }
public virtual string disposiciones { get; set; }
public virtual plaserv plaserv { get; set; }
}
}
I need for this class only the string type to be converted into TEXT in database
If I change by
public virtual string[] reconocimiento { get; set; }
FluentNHibernate takes a BLOB data type
I can do something like?
public class plaparteMappingOverride : IAutoMappingOverride<plaparte>
{
public void Override(AutoMapping<plaparte> mapping)
{
Map(x => x.disposiciones).CustomSqlTypeIs("TEXT");
}
}
To solve the problem I am using:
using System.ComponentModel.DataAnnotations;
...
public class plaparte
{
...
[StringLength(4000)]
public virtual string disposiciones { get; set; }
To create TEXT fields
[Update]
For work I need to create the next class
class StringLengthConvention : AttributePropertyConvention<StringLengthAttribute>
{
protected override void Apply(StringLengthAttribute attribute, IPropertyInstance instance)
{
instance.Length(attribute.MaximumLength);
}
}
is also necessary to add the convention Fluent automap
Like
static AutoPersistenceModel CreateAutomappings()
{
return AutoMap.AssemblyOf<plaparte>(new mapAutomapConfiguration())
.Conventions.Setup(c =>
{
c.Add<StringLengthConvention>();
});
}