ASP.NET MVC3 EF model Inheritance Cannot implicitly convert type - asp.net

I am sure i am just missing some pretty basic here, but i can't seem to figur it out.. maybe because its been a while since i have been on the .NET platform.
Anyway, I have this database structure i the ASP.NET MVC3 framework where i have "Coruse", "Tool" and "ToolADL"(Inheritance from Tool). A "Course" can have one-or-more "Tools" where one of the "Tool"-types is "ToolADL".
Models/Course.cs:
public class Course {
[Key]
public int CourseID { get; set; }
[Required(ErrorMessage = "{0} er påkrævet")]
[Display(Name = "Værktøj")]
public virtual ICollection<Tool> Tools { get; set; }
}
Models/Tool.cs:
public abstract class Tool {
public Tool(){
Priority = 0;
}
[Key]
public int ToolID { get; set; }
[Required]
public int CourseID { get; set; }
[Required]
public int Priority { get; set; }
}
Models/ToolADL.cs:
public class ToolADL : Tool {
[Required]
public string Image { get; set; }
}
aaand the Models/ProjectContext:
public class ProjectContext : DbContext {
// Course context
public DbSet<Course> Courses { get; set; }
// Tools
public DbSet<Tool> Tools { get; set; }
// ToolADL
public DbSet<ToolADL> ToolADLs { get; set; }
}
Now when i try to create the controller and connect to DbContext and the Model to it so the entity framwork can do its magic, I get the following error in the ToolADL controller Details function (and others) where time i use "find()":
ToolADLController.Details(int):
private ProjectContext db = new ProjectContext();
public ViewResult Details(int id){
ToolADL tooladl = db.Tools.Find(id);
return View(tooladl);
}
Error 1 Cannot implicitly convert type 'Project.Models.Tool'
to 'caREhab_community.Models.ToolADL'. An explicit conversion exists
(are you missing a cast?) C:\Users\Thor\Documents\Visual Studio
2010\Projects\Project\Project\Project\ToolADLController.cs 29 31 Project
(I changed the name of the orginal project to "Project")
I simply cannot figur out what I am doing wrong, Is it wrong types, some really basic about Inheritance i left out or something else?
Hope some kind soul can tell me why I am an idiot and can't figure this out :)

If object that is returned by db.Tools.Find(id) is of type ToolADL then you should do:
ToolADL tooladl = db.Tools.Find(id) as ToolADL;
After that You'll have your object or null.
If it's not of type ToolADL then you can't do this because:
When You have:
public class A { }
public class B : A { }
You can not do something like this:
A a = new A();
B b = a;
This is in fact a basic truth about inheritance.
You might change this implicit conversion to explicit on by doing:
B b = (B)a;
Then your code would compile but You would get a runtime exception:
Unable to cast object of type 'A' to type 'B'.
To make it work You would have to specify an explicit conversion like this:
public class A
{
public static explicit operator B(A a)
{
return new B();
}
}
But this will give you yet another compile time error:
'A.explicit operator B(A)': user-defined conversions to or from a
derived class are not allowed

Related

ASP.net Core eager loading, let included object be null

I am getting all customers and including their linked operator.
The only catch is a customer can exist without an operator.
The problem I am having is when i try include the operator any customer that doesn't have a linked operator is not retrieved is there a way to still retrieve all my customers and if thy do not have an operator just have the operator object within the customer be null?
-get all customers method
public List<Customer> GetAllWithRelations()
{
return Context.Set<Customer>()
.Include(cp => cp.Operator).ToList();
}
-Cusomer object
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public int? OperatorId { get; set; }
[ForeignKey("OperatorId")]
public virtual Operator Operator { get; set; }
}
-Operator Object
public class Operator
{
public int Id { get; set; }
public string Name { get; set; }
}
Although you did not specify a tag for this, by using the .Include I'm guessing it's a EntityFramework Core linq which is breaking.
I've came across the same case on EF whenever the relationship is not set to allow nulls. So, for instance, your mapping might be explicitly setting it to be required or somehow you're not setting it and EF defaults are stablishing a required map between Customer and Operator.
Just set it to optional wherever you're building your model mappings and you'll get the desired behavior.
See: https://learn.microsoft.com/en-us/ef/core/modeling/required-optional

ASP.NET Core Entity Framework get related data object

Every time I am trying to get a related object I get error
Object reference not set to an instance of an object
Relevant code:
public class Project
{
public int ProjectId { get; set; }
public string ProjName { get; set; }
public string Description { get; set; }
public virtual List<Developer> MyDevs { get; set; }
}
public class Developer
{
public string Name { get; set; }
public string Skills { get; set; }
public string Email { get; set; }
public virtual Project MyProj { get; set; }
}
//define relationship using fluent api, under AppDbContext
modelBuilder.Entity<Developer>()
.HasOne(d => d.MyProj)
.WithMany(p => p.MyDevs)
.HasForeignKey("ProjectForeignKey");
Add-migration and update-database give no error, but I am not able to find the myDev column in the Project table. I am not able to find the myProj column in the Developer table either, only the foreignkey column.
Running the following seed method adds one project and one developer to the db as expected.
public static void Seed(IApplicationBuilder applicationBuilder)
{
AppDbContext context = applicationBuilder.ApplicationServices.GetRequiredService<AppDbContext>();
Project ProjA = new Project { ProjName = "handyApp", Description = "a dummy Project" };
context.Project.Add(projA);
Developer FirstDev = new Developer { UserName = "John Smith", Skills = "C#", Email = "jsmith#dummymail.com", MyProj = ProjA};
context.Developer.Add(FirstDev);
context.SaveChanges();
}
Then running the following code hits the "Object reference not set to an instance of an object" exception.
Developer Dev = context.Devs.Find(1);
string name = Dev.MyProj.ProjName; //put a break point here, the dubugger tells me Dev.MyProj is null
Please can anyone help to identify what is wrong with my relationship definition.
As # Ivan Stoev pointed out, Lazy loading is not yet supported by EF Core.
https://learn.microsoft.com/en-us/ef/core/querying/related-data

Xamarin Forms - Using SQLite and SQLite Extensions to implement foreign keys

I'm new to Xamarin forms and am up to the point where I now want to be persisting data entered by the user to an Sqlite db. Thankfully, there all plenty of examples to get you started, but thats as far as the help goes... I'm trying to implement a relationship between two entities 'Session' and 'HandHistory'.
A Session can have multiple HandHistories - immediately I saw that some sort of foreign key would be needed here to link these tables/entities together. I read in multiple articles and stack overflow questions that the standard 'sqlite-net-pcl' (by Frank A.Krueger) package offers nothing in terms of foreign keys, and that in order to acquire the functionality I needed to use the SQLiteNetExtensions library. I referred to this article for help:
https://bitbucket.org/twincoders/sqlite-net-extensions/overview
My entities look like this:
Session:
using SQLite;
using SQLiteNetExtensions.Attributes;
namespace PokerSession.Models
{
[Table("Session")]
[AddINotifyPropertyChangedInterface]
public class Session
{
public Session(bool newSession)
{
if (newSession)
{
CurrentlyActive = true;
//HandHistories = new ObservableCollection<HandHistory>();
}
}
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public SessionType SessionType { get; set; } = SessionType.Tournament;
public string Location { get; set; }
public DateTime Date { get; set; } = DateTime.Now;
public string GeneralNotes { get; set; }
public int MoneyIn { get; set; }
public int MoneyOut { get; set; }
public int ProfitLoss
{
get
{
var p = MoneyOut - MoneyIn;
if (p < 0)
return 0;
return p;
}
}
/// <summary>
/// If the session has not been completed, set this to true
/// </summary>
public bool CurrentlyActive { get; set; }
[OneToMany(CascadeOperations = CascadeOperation.All)]
public ObservableCollection<HandHistory> HandHistories { get; set; }
}
}
HandHistory:
using SQLite;
using SQLiteNetExtensions.Attributes;
namespace PokerSession.HandHistories
{
[Table("HandHistory")]
[AddINotifyPropertyChangedInterface]
public class HandHistory
{
public HandHistory()
{
}
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[ForeignKey(typeof(Session))]
public int SessionId { get; set; }
[ManyToOne]
public Session Session { get; set; }
}
}
I also followed this article for the platform specific implementations for obtaining the SQLiteConnection for the local db:
https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/databases/
The error I'm getting:
'SQLiteConnection' does not contain a definition for 'UpdateWithChildren' and the best extension method overload 'WriteOperations.UpdateWithChildren(SQLiteConnection, object)' requires a receiver of type 'SQLiteConnection' PokerSession.Android, PokerSession.iOS C:\Poker Notes Live\PokerSession\PokerSession\PokerSession\Services\DataService.cs 46 Active
private SQLiteConnection _database;
public DataService()
{
_database = DependencyService.Get<ISqLite>().GetConnection();
_database.GetTableInfo("HandHistory");
_database.CreateTable<Session>();
_database.CreateTable<HandHistory>();
var session = new Session(false)
{
Location = "Test Location",
Date = new DateTime(2017, 08, 26),
MoneyIn = 35,
MoneyOut = 0,
SessionType = SessionType.Tournament,
GeneralNotes = "blah blah"
};
var hh = new HandHistory();
_database.Insert(session);
_database.Insert(hh);
session.HandHistories = new ObservableCollection<HandHistory> {hh};
_database.UpdateWithChildren(session);
}
So basically it's not allowing me to use the SQLite Extension methods with my SQLiteConnection object (_database) which is confusing as this is the whole point behind the Extension methods? Surely they're made to work with the SQLiteConnection object?? I've also noticed through my playing around that there seems to be two different types of SQLiteConnection... The one I'm currently using is in the 'SQLite' namespace, and another one in the SQLite.Net namespace. I have checked the one in the SQLite.Net namespace and it does seem to like the Extension methods but it requires me to change my platform specific implementation for obtaining the SQLiteConnection, but it would fail at runtime (complaining about my Session entity not having a PK??).
Quite a long winded question I know but it's better to provide more information than not enough, and I'm sure there must be others experiencing similar problems so please comment and offer any help possible, thank you.

ASP.NET Web API - Entity Framework - 500 Internal Server Error On .Include(param => param.field)

I am currently working on a Web API project with a Database-First method using Entity Framework (which I know is not the most stable of platforms yet), but I am running into something very strange.
When the GET method within my APIController tries to return all records in a DbSet with a LINQ Include() method involved such as this, it will return a 500 error:
// GET api/Casinos
public IEnumerable<casino> Getcasinos()
{
var casinos = db.casinos.Include(c => c.city).Include(c => c.state);
return casinos.AsEnumerable();
}
Yet, this method works fine, and returns my data from within my database:
// GET api/States
public IEnumerable<state> Getstates()
{
return db.states.AsEnumerable();
}
So I have proved in other instances that if it returns the entities without LINQ queries, it works great, yet when there is an Include method used upon the DbContext, it fails.
Of course, trying to find this error is impossible, even with Fiddler, Chrome/Firefox dev tools, and adding in GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
If anyone has resolved this, it would be nice to know a nice resolution so I can start returning my data! Thanks!:)
P.S. I am using SQL Server 2012
This is happening due to error in serialization (Json/XML). The problem is you are directly trying to transmit your Models over the wire. As an example, see this:
public class Casino
{
public int ID { get; set; }
public string Name { get; set; }
public virtual City City { get; set; }
}
public class State
{
public int ID { get; set; }
public string Name { get; set; }
[XmlIgnore]
[IgnoreDataMember]
public virtual ICollection<City> Cities { get; set; }
}
public class City
{
public int ID { get; set; }
public string Name { get; set; }
public virtual State State { get; set; }
[XmlIgnore]
[IgnoreDataMember]
public virtual ICollection<Casino> Casinos { get; set; }
}
public class Context : DbContext
{
public Context()
: base("Casino")
{
}
public DbSet<Casino> Casinos { get; set; }
public DbSet<State> States { get; set; }
public DbSet<City> Cities { get; set; }
}
Pay attention to the XmlIgnore and IgnoreDataMember. You need to restrict avoiding serialization so it doesn't happen in circular manner. Further, the above model will still not work because it has virtual. Remove virtual from everywhere namely City, Cities, Casinos and State and then it would work but that would be inefficient.
To sum up: Use DTOs and only send data that you really want to send instead of directly sending your models.
Hope this helps!
I had same problem in ASP.Net Core Web Api and made it working with this solution:
Add Microsoft.AspNetCore.Mvc.NewtonsoftJson nuget package to web api project.
and in Startup.cs class in ConfigureServices method add this code:
services.AddControllersWithViews().AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);

The member with identity does not exist in the metadata collection. Parameter name: identity

We are using EF Code First 4.3.1.
We are developing an ASP.NET Web Role referring to multiple class libraries.
There are two class libraries each containing classes and an individual DBcontext.
Lets say the Library1 has classes A and B.
DBcon1: DbSet and DbSet
Lets say the Library2 has classes C and D.
Class C{
[Key]
public int CId{ get; set;}
[Required]
public virtual A referencedA {get; set;}
}
DBcon2: DbSet<C> and DbSet<D>
When I try to use the DBcon2 as such:
using (var con = new DBcon2())
{
C vr = new C();
vr.CId= 1;
vr.referencedA = DBCon1.As.First();
con.Cs.Add(vr);
con.SaveChanges();
}
I get an exception as:
"The member with identity does not exist in the metadata collection.
Parameter name: identity"
Both DBCon1 and DBcon2 are using the sane SQL Server Database "SampleDB".
Please point me in the right direction.
I got this error and fixed it by not trying to set the navigation property in the related table, just set the foreign key id instead
eg
public class Student()
{
public int StudentId { get; set; }
public string StudentName { get; set; }
public int CourseId { get; set; }
public virtual Course Course { get; set; }
}
public class Course()
{
public int CourseId { get; set; }
public string CourseName { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
Main code:
var myCourse = new Course();
var myCourseId = 1;
var student = new Student() {
CourseId = myCourseId
// Course = myCourse <-- this would cause the error
}
Might not be your issue but maybe it will point you in the right direction and hopefully will help someone else.
The exception is a bit cryptic, but pretty clear if you realise that a context needs information about entities (metadata) to be able to write sql statements. Thus, your DBcon2 context has no clue where to find the primary key of an A, because it has no metadata about A.
You could however set an integer property A_Id (or the like), but then you'll have to write custom code to resolve it to an A.
Another option is to merge (parts of) the contexts, if possible.

Resources