Code First : Context fields are null - entity-framework

Here is my context:
public class ContentContext : DbContext
{
public ContentContext() : base("Name=CodeFirstDatabase") { }
public DbSet<Article> Articles;
public DbSet<ArticleTag> ArticleTags;
}
connection string:
<add name="CodeFirstDatabase" providerName="System.Data.SqlClient" connectionString="Server=X-ПК\SQLEXPRESS;Database=Products;Trusted_Connection=true;"/>
Global.asax:
Database.SetInitializer(new CreateDatabaseIfNotExists<ContentContext>());
HomeController:
public ActionResult Index()
{
ContentContext context = new ContentContext();
context.Database.Initialize(true);
Article a = new Article() { Text = "TEXT" };
context.Articles.Add(a);
context.SaveChanges();
return View();
}
Entities:
public class Article
{
public int Id { get; set; }
public string Author { get; set; }
public string Text { get; set; }
public virtual ICollection<ArticleTag> ArticleTags { get; set; }
}
public class ArticleTag
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Article Article { get; set; }
}
Database created as expected.But no tables created in it and I get null reference exception when I try add new Article. Any ideas? Thanks.

Change your DBSet<> in ContentContext to properties (instead of fields):
public DbSet<Article> Articles { get; set; }
public DbSet<ArticleTag> ArticleTags { get; set; }

Related

How do I fix this SQLite error: SQLite Error 1: 'table "StudentCourses" already exists'

I'm creating a CRUD project in asp.net entity framework, and from my understanding, in order to see the data on the HTML page I have to scaffold the pages. For example I have two entity models Student and Major
This is the Student entity
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
[ForeignKey("Major")]
public int? MajorId { get; set; }
public Major Major { get; set; }
[ForeignKey("Advisor")]
public int AdvisorId { get; set; }
public Advisor Advisor { get; set; }
public ICollection<StudentCourses>? StudentCourses { get; set; }
}
This is the Major entity
public class Major
{
public int MajorId { get; set; }
public string MajorName { get; set; }
public ICollection<Student> Students { get; set; }
public ICollection<Advisor> Advisors { get; set; }
public ICollection<MajorCourse> MajorCourses { get; set; }
}
If I want to see the Student data I have to create a Students folder and add a new Scaffolding along with a DbContext like your_namespace.Data.StudentContext. I would also have to follow the same steps for the Major entity but am I correct to use another DbContext? For example: your_namespace.Data.MajorContext. This is what I have done but when I try to make migrations and update the database in the your_namespace.Data.MajorContext, I get an error that reads SQLite Error 1: 'table "StudentCourses" already exists'.`
How do I fix this error?
I should also add the Context classes:
This is the StudentContext class:
public class AdvismentContext : DbContext
{
public AdvismentContext(DbContextOptions<AdvismentContext> options)
: base(options)
{
}
public DbSet<Student> Students { get; set; }
public DbSet<Major> Majors { get; set; }
public DbSet<Advisor> Advisors { get; set; }
public DbSet<Course> Courses { get; set; }
public DbSet<MajorCourse> MajorCourses { get; set; }
public DbSet <StudentCourses> StudentCourses{ get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>()
.ToTable("Students");
modelBuilder.Entity<Major>()
.ToTable("Majors");
modelBuilder.Entity<Advisor>()
.ToTable("Advisors");
modelBuilder.Entity<Course>()
.ToTable("Courses");
//modelBuilder.Entity<MajorCourse>()
// .ToTable("MajorCourse");
//.HasKey(mc => new { mc.MajorId, mc.CourseId });
}
And this is the MajorContext class:
public class MajorContext : DbContext
{
public MajorContext (DbContextOptions<MajorContext> options)
: base(options)
{
}
public DbSet<Advisment.Models.Major> Major { get; set; } = default!;
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Major>()
.ToTable("Major");
//modelBuilder.Entity<MajorCourse>() This is commented out because I was getting the same error that the table already exists.
// .ToTable("MajorCourse");
}
}
What am I doing wrong?

EF: validation error for 1:0..1 relationship in data model with navigation properties

I have this simple data model of some reservations and theirs cancellations:
[Table("ReservationCreation")]
public class ReservationCreation
{
[Key()]
public int ReservationCreationId { get; set; }
[InverseProperty("ReservationCreation")]
public virtual ReservationCancellation ReservationCancellation { get; set; }
}
[Table("ReservationCancellation")]
public class ReservationCancellation
{
[Key()]
[ForeignKey("ReservationCreation")]
public int ReservationCancellationId { get; set; }
[Required]
[ForeignKey("ReservationCancellationId")]
[InverseProperty("ReservationCancellation")]
public virtual ReservationCreation ReservationCreation { get; set; }
}
public class DbContext : System.Data.Entity.DbContext
{
public DbContext() : base(#"DefaultConnection") { }
public DbSet<ReservationCancellation> ReservationCancellation { get; set; }
public DbSet<ReservationCreation> ReservationCreation { get; set; }
}
internal sealed class Configuration : DbMigrationsConfiguration<DbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
}
}
Here is the code of the test. First the reservation is created and then it is cancelled.
When the cancellation record is being saved into database then an exception is thrown "The ReservationCreation field is required".
How can I create cancellation record only from the reservation's ID and at the same time have the navigation properties defined?
class Program
{
static void Main(string[] args)
{
int reservationId;
// create reservation
using (var db = new DbContext())
{
var reservation =
db.ReservationCreation.Add(
new ReservationCreation());
db.SaveChanges();
reservationId = reservation.ReservationCreationId;
}
// cancel reservation by its Id
using (var db = new DbContext())
{
var cancellation =
db.ReservationCancellation.Add(
new ReservationCancellation
{
ReservationCancellationId = reservationId
});
try
{
// an exception is thrown
db.SaveChanges();
}
catch(DbEntityValidationException ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
foreach (var err in ex.EntityValidationErrors.SelectMany(x_ => x_.ValidationErrors))
System.Diagnostics.Debug.WriteLine($"!!!ERROR!!! {err.PropertyName}: {err.ErrorMessage}");
}
}
}
}
I did not find any way how to modify the data model annotations. If I remove [Required] from ReservationCreation property then I am not able to create the migration {or connect to the database with that data model).
Your mixing things up in your ReservationCancellation model.
In your ReservationCreation property you are referring to the primary key entity instead of the ReservationCreation property.
Try this.
[Table("ReservationCancellation")]
public class ReservationCancellation
{
[Key()]
public int ReservationCancellationId { get; set; }
[ForeignKey("ReservationCreation")]
public int ReservationCreationId { get; set; }
[Required]
public virtual ReservationCreation ReservationCreation { get; set; }
}
Update
Since you want only one cancellation per creation, you can do this using a simpler model.
[Table("ReservationCreation")]
public class ReservationCreation
{
[Key()]
public int ReservationCreationId { get; set; }
public virtual ReservationCancellation ReservationCancellation { get; set; }
}
[Table("ReservationCancellation")]
public class ReservationCancellation
{
[Key()]
public int ReservationCancellationId { get; set; }
public virtual ReservationCreation ReservationCreation { get; set; }
}
I followed the recommendations from #dknaack and my final solution of this problem is this data model:
[Table("ReservationCreation")]
public class ReservationCreation
{
[Key()]
public int ReservationCreationId { get; set; }
[InverseProperty("ReservationCreation")]
public virtual ReservationCancellation ReservationCancellation { get; set; }
}
[Table("ReservationCancellation")]
public class ReservationCancellation
{
[Key()]
[ForeignKey("ReservationCreation")]
public int ReservationCancellationId { get; set; }
[ForeignKey("ReservationCancellationId")]
public virtual ReservationCreation ReservationCreation { get; set; }
}

Returning Entity with its children

Hi I am trying to return all vehicles with their recorded mileage through an api using ASP.Net Core with the following code:
// GET: api/values
[HttpGet]
public IEnumerable<Vehicle> Get()
{
return _context.Vehicles.Include(m=>m.Mileages).ToList();
}
However this only returns the first vehicle with its mileages and not the others (there are five dummy vehicles in the db all with an initial mileage).
If I change the code to:
// GET: api/values
[HttpGet]
public IEnumerable<Vehicle> Get()
{
return _context.Vehicles.ToList();
}
it returns the full list of vehicles but no mileage.
My class files are:
public class Vehicle
{
public Vehicle()
{
Mileages = new List<Mileage>();
}
public int Id { get; set; }
public string Registration { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public Marked Marked { get; set; }
public ICollection<Mileage> Mileages { get; set; }
}
and
public class Mileage
{
public int Id { get; set; }
public DateTime MileageDate { get; set; }
public string RecordedMileage { get; set; }
//Navigation Properties
public int VehicleId { get; set; }
public Vehicle Vehicle { get; set; }
}
thanks for looking!
Tuppers
you can have them auto-load (lazy loading) using proxies... but for that, your foreign entities and collections must be marked virtual in your POCOs:
public class Mileage
{
public int Id { get; set; }
public DateTime MileageDate { get; set; }
public string RecordedMileage { get; set; }
//Navigation Properties
public int VehicleId { get; set; }
public virtual Vehicle Vehicle { get; set; }
}
public class Vehicle
{
public Vehicle()
{
Mileages = new List<Mileage>();
}
public int Id { get; set; }
public string Registration { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public Marked Marked { get; set; }
public virtual ICollection<Mileage> Mileages { get; set; }
}
The proxy creation and lazy loading turned on, but that's the default in EF6.
https://msdn.microsoft.com/en-us/data/jj574232.aspx
Let me know if this works.
Well after a lot of searching I managed to find a solution. I used the following:
[HttpGet]
public IEnumerable<VehicleDto> Get()
{
var query = _context.Vehicles.Select(v => new VehicleDto
{
Registration = v.Registration,
Make = v.Make,
Model = v.Model,
Marked = v.Marked,
Mileages = v.Mileages.Select(m => new MileageDto
{
MileageDate = m.MileageDate,
RecordedMileage = m.RecordedMileage
})
.ToList(),
})
.ToList();
return (IEnumerable<VehicleDto>) query.AsEnumerable();
this doesn't seem to be the most elegant way of doing this, if anyone could offer any advice but it does return what is required.
The DTO's look like:
public class VehicleDto
{
public string Registration { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public Marked Marked { get; set; }
public ICollection<MileageDto> Mileages { get; set; }
}
and
public class MileageDto
{
public DateTime MileageDate { get; set; }
public string RecordedMileage { get; set; }
}
Thanks for taking the time to look at this
Tuppers

InvalidOperationException: The entity type 'object' requires a key to be defined

Entity-framework 7.
[Table("Settings")]
public class Setting
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public object DefaultValue { get; set; }
public string Classification { get; set; }
public FacilitySettingOverride FacilitySettingOverride { get; set; }
}
[Table("FacilitySettingOverride")]
public class FacilitySettingOverride
{
[Key]
[ForeignKey("FacilityId")]
public int FacilityId { get; set; }
public object Value { get; set; }
[ForeignKey("SettingId")]
public int SettingId { get; set; }
public virtual ICollection<Setting> Settings { get; set; }
}
[Table("Facilities")]
public class Facility
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<FacilitySettingOverride> FacilitySettingOverrides { get; set; }
}
When run the code
private IEnumerable<FacilitySettingOverride> GetFacilityBandwidthSettings
{
get
{
List<FacilitySettingOverride> settingList;
using (SettingDbContext context = new SettingDbContext())
{
settingList = context.FacilitySettingOverride.ToList();
}
return settingList;
}
}
Then get the exception:
InvalidOperationException: The entity type 'object' requires a key to be defined.
The context is:
public class SettingDbContext : DbContext
{
public DbSet<Setting> Settings { get; set; }
public DbSet<FacilitySettingOverride> FacilitySettingOverride { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=13.53.63.74;Initial Catalog=AAAAA;User ID=sa;password=password);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}
However if I change the object to string for Value or DefaultValue in POCO then no exception. But the type in the database is sql_variant. I have to use the type object.
It seems that Data annotations are not yet supported so you will need to use the Fluent API for configuration.
See: https://github.com/aspnet/EntityFramework/issues/1913#issuecomment-86662854

EF 6 Code First Mapping one-to-many

Can someone please help me with mapping the following hierarchy with EF 6 code first? I can find anything useful for the below example in the documentation.
namespace Contacts {
public class Person
{
public Person()
{
this.Emails = new HashSet<Email>();
}
public long Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<Email> Emails { get; set; }
}
public class Company
{
public Company()
{
this.Emails = new HashSet<Email>();
}
public long Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Email> Emails { get; set; }
}
public class Email
{
public string Value { get; set; }
public string Label { get; set; }
public string TargetId { get; set; }
public string TargetType { get; set; }
}
}
TargetType can be set to Company or Person depending on the entity that contains the Email instance.
DB Schema: