Query Parent Class EF inheritence linq query - c#

Hello everyone so here is my basic EF class structure:
public abstract class StandardEngineeredModel
{
[Key]
public string ModelNumber { get; set; }
public int VoltageInput { get; set; }
}
public class DualRatedInputEngineeredModel : StandardEngineeredModel
{
public int SinglePhaseVoltageInput { get; set; }
public string SinglePhaseHzInput { get; set; }
public decimal SinglePhaseAmpsInput { get; set; }
public bool SeparateInput { get; set; }
}
And my context:
public class LabelPrintingContext : DbContext
{
public virtual DbSet<StandardEngineeredModel> StandardEngineeredModels { get; set; }
}
What I am trying to do is query for a StandardEngineeredModel. Here is an example of a query I tried:
public StandardEngineeredModel GetEngineeredOrder(string modelNumber)
{
using (context = new LabelPrintingContext())
{
return (from s in context.StandardEngineeredModels
where s.ModelNumber == modelNumber
select s).FirstOrDefault();
}
}
But when executing this it says invalid column name SeparateInput which seems to be happening because of the extra column being added to my StandardEngineeredModels table due to the DualRatedInputEngineeredModel inheriting from it. Not sure how to go about this, I don't want to return an Iqueryable, but no matter what I try it tells me the SeparateInput is an invalid column name.
I also tried casting it first and get the same error:
public StandardEngineeredModel GetEngineeredOrder(string modelNumber)
{
using (context = new LabelPrintingContext())
{
return (from s in context.StandardEngineeredModels.OfType<StandardEngineeredModel>()
where s.ModelNumber == modelNumber
select s).FirstOrDefault();
}
}
Do I need to make a DTO or something? Am I just doing this completely wrong?
Thanks in advance for any opinions / help!

Related

LINQ Projection and loading child objects

Having an issue with projection and getting child objects to load. The following is simplified code to represent the logic I'm trying to implement, not the actual code.
public class TicketItem
{
public int TicketItemId { get; set; }
public string TicketReason { get; set; }
public Station Station { get; set; }
public TicketOwner TicketOwner { get; set; }
}
public class Station
{
public int StationId { get; set; }
public string Name { get; set; }
}
public class TicketOwner
{
public int TicketOwnerId { get; set; }
public Employee Employee { get; set; }
public Organization Organization { get; set; }
}
public class Employee
{
public int EmployeeId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Organization
{
public int OrganizationId { get; set; }
public string Code { get; set; }
public string Name { get; set; }
}
public class CommonReasons
{
public int CommonReasonId { get; set; }
public string Reason { get; set; }
}
public TicketItem GetById(int id)
{
var query = from i in _dataContext.TicketItems
.Include("Station")
.Include("TicketOwner.Employee")
.Include("TicketOwner.Organization")
join r in _dataContext.CommonReasons on i.TicketReason equals r.CommonReasonId.ToString() into r1
from r2 in r1.DefaultIfEmpty()
where i.TicketItemId == id
select new TicketItem {
TicketItemId = i.TicketItemId,
TicketReason = r2.Reason == null ? i.Reason : r2.Reason,
Station = i.Station,
TicketOwner = i.TicketOwner
};
return query
.AsNoTracking()
.FirstOrDefault();
}
Most the code is self-explanatory. The part that is indirectly causing the trouble would be the relationship between TicketItem.TicketReason property (a string) and the CommonReasons entity. From the user interface side, the end-user has an input field of "Reason", and they can select from "common" reasons or input an adhoc reason. They original developer chose to have the TicketReason property contain either the key ID from the CommonReasons table (if the user selected from drop-down) or the adhoc reason typed in.
So, to handle this logic in the linq query, the only way I have found is to do a left join between TicketItem.TicketReason and CommonReasons.CommonReasonId, then use projection to modify the TicketReason column returning either the common reason text or adhoc text. If there is a different way to do this that would get me around the trouble I'm having with projection/include, I'm all ears.
For the "reason" logic, this query works, returning the proper text. The trouble is that none of the "grand-child" objects are returning, i.e. TicketItem.TicketOwner.Employee, TicketItem.TicketOwner.Organization. How do I get those objects to return also?
Changing the structure of the tables would be an absolute last resort, just based on the amount of code that would have to change. There are other spots in the code that are using the above logic but don't need the child objects.
Any help would be appreciated. Hope I've explained enough.

c# asp.net make a get request on relational table with entity framework database

I am trying to get data from a table with a get request with a controller. When I make the request with a normal table (TestTable) it is ok, but if I make the request with a relational table I get the fail message:
"The 'ObjectContent`1' type failed to serialize the response body for
content type 'application/xml; charset=utf-8'."
My controller (Mdata):
namespace ScThAsp.Controllers
{
public class MDataController : ApiController
{
public IEnumerable<Måledata> Get()
{
using (var e = new SCTHDBEntities())
{
return e.Måledata.ToList();
}
}
public TestTable Get(int id)
{
using (SCTHDBEntities entities = new SCTHDBEntities())
{
return entities.TestTable.FirstOrDefault(e => e.Id == 1);
}
}
}
}
My Table for måledata is:
public partial class Måledata
{
public int MDid { get; set; }
public Nullable<int> BBid { get; set; }
public Nullable<decimal> Måling1 { get; set; }
public Nullable<decimal> Måling2 { get; set; }
public Nullable<decimal> Måling3 { get; set; }
public Nullable<decimal> Måling4 { get; set; }
public Nullable<System.DateTime> RegTid { get; set; }
public virtual BuildBoard BuildBoard { get; set; }
}
My database looks like:
Database
See link..
I think I mayby should make a inner join with the other table connected to Måledata table - I am not sure how to do that in a EF environment.
I have really tried a lot now - hope for an answer. Thanks
Your class Måledata contains more data that you presented (it is marked as partial) and probably contains stuff related to EF. This magic stuff is not serializable. To avoid problem rewrite results to a plain object with properties you need. This object must be serializable (if contains plain properties and classes it will).
Building upon Piotr Stapp's answer you need to create a DTO (Data Transfer Object) for your Måledata which contains properties as your model, Måledata other than the EF properties. Use some sort of Mapper, maybe AutoMapper to map the required properties in your final response.
public class MaledataDTO
{
public int MDid { get; set; }
public int? BBid { get; set; }
public decimal? Måling1 { get; set; }
public decimal? Måling2 { get; set; }
public decimal? Måling3 { get; set; }
public decimal? Måling4 { get; set; }
public DateTime? RegTid { get; set; }
//... other properties
}
public IEnumerable<MaledataDTO> Get()
{
using (var e = new SCTHDBEntities())
{
var result = e.Måledata.ToList();
return Mapper.Map<List<MaledataDTO>>(result);
}
}
I found 2 solutions.
1) Solution was with Automapper (thanks Abdul). Installing automapper and a Using Automapper. Added a class called MåledataDTO : ` public class MåledataDTO
{
public int MDid { get; set; }
public int? BBid { get; set; }
public decimal? Måling1 { get; set; }
public decimal? Måling2 { get; set; }
public decimal? Måling3 { get; set; }
public decimal? Måling4 { get; set; }
public DateTime? RegTid { get; set; }
//... other properties
}
`
In my controller I used the following code
public IEnumerable<MåledataDTO> Get()
{
using (var e = new SCTHDBEntities())
{
Mapper.Initialize(config =>
{
config.CreateMap<Måledata, MåledataDTO>();
});
var result = e.Måledata.ToList();
return Mapper.Map<List<MåledataDTO>>(result);
2: In the second solution: In the picture you see the relations bewtween the tables - made in VS - but that creates a problem in the tables Get SET classes. The relation creates a Virtual object in the class - like mentioned before
public virtual BuildBoard BuildBoard { get; set; }
If you delete the relations and make the public partial class Måledata like
in this video
https://www.youtube.com/watch?v=4Ir4EIqxYXQ
the controller should then have one of two solutions:
using (SCTHDBEntities e = new SCTHDBEntities()) {
//this works
//var knud = new List<Måledata>();
//knud = (e.BuildBoard.Join(e.Måledata, c => c.BBid, o => o.BBid,
// (c, o) => o)).ToList();
//return knud;
//this works too
return (from p in e.BuildBoard
where p.BBid == 1
from r in e.Måledata
where r.BBid == p.BBid
select p).ToList();
That was that
Gorm

Entity Framework query with simple join

I am using Entity Framework 6 in a project and am having trouble creating a query.
Say my classes are defined like:
public class MyContext : DbContext
{
public MyContext(string connectionString) : base(connectionString)
{
}
public DbSet<EntityXXX> XXXSet { get; set; }
public DbSet<EntityYYY> YYYSet { get; set; }
}
public class EntityXXX
{
public string XXXName { get; set; }
public int id { get; set; }
public int YYYid { get; set; }
}
public class EntityYYY
{
public string YYYName { get; set; }
public int id { get; set; }
}
The YYYid property of EntityXXX is the 'id' of the EntityYYY instance that it relates to.
I want to be able to fill a Grid with rows where the first Column is XXXName and the second column is YYYName (from its related EntityYYY), but I can't see how to do this?
I'm sure it's really simple, but I'm new to EF.
You need to put a virtual navigation property on your EntityXXX
public virtual EntityYYY YYY { get; set; }
Then you can do a projection:
db.XXXSet
.Select(x => new { x.XXXName, YYYName = x.YYY.YYYName })
.ToList();
Which will get you the list you need.

EntityFrameworkCore using wrong column in query

I am trying to write my first web api with .net core. I am using VS2017 and core 1.1. I've got everything working except for one of my objects (I've tried it with that last line commented and uncommented...it makes no difference):
public class Tag
{
public int ID { get; set; }
public string Name { get; set; }
public bool ShowInFilter { get; set; }
public ICollection<SubscriberTag> SubscriberTags { get; set; }
}
My repository code looks like this:
private SubscriptionContext db;
public TagRepository(SubscriptionContext context) { db = context; }
public Tag Find(int key) => db.Tags.SingleOrDefault(a => a.ID == key);
That is being called from my TagController:
private iTagRepository TagItems { get; set; }
public TagController(iTagRepository tagItems) {TagItems = tagItems; }
[HttpGet("{id}", Name = "GetTag")]
public IActionResult Get(int id) { return new ObjectResult( TagItems.Find(id) ); }
The problem is when I run it, the query that is executed is:
exec sp_executesql
N'SELECT TOP(2) [a].[ID], [a].[Name],
[a].[ShowInFilter], [a].[SubscriberID]
FROM [Tags] AS [a]
WHERE [a].[ID] = #__key_0',N'#__key_0 int',#__key_0=1
which throw and error because Tags doesn't contain a column called SubscriberID.
I've searched all my code and SubscriberID only shows up two places (in other classes which are not being used here). I have no partial classes in my entire project (saw that was an issue on a related question.)
Why is EF adding this column to its query and how do I fix it?
As requested here is the class that contains subscriberID:
public class SubscriberTag
{
public long ID { get; set; }
public long subscriberID { get; set; }
public int tagID { get; set; }
public Subscriber Subscriber { get; set; }
public Tag Tag { get; set; }
}
Subscriber class (lots of irrelevant properties removed):
public class Subscriber
{
public Subscriber()
{
//a few value initalizers/defaults
}
public long ID { get; set; }
[StringLength(200)]
public string FirstName { get; set; }
//.......
public ICollection<Subscribers.Models.Subscription> Subscriptions { get; set; }
public ICollection<Subscribers.Models.Tag> Tags { get; set; }
}
Because of the Property Tags on Subscriber:
public ICollection<Subscribers.Models.Tag> Tags { get; set; }
Entity Framework expects the Tag object to have a foreign-key to Subscriber so it builds a query with it. It looks like to configure the many-to-many relationship needs to change the property to:
public ICollection<Subscribers.Models.SubscriberTag> SubscriberTag{ get; set; }
Configuring a Many-to-Many Relationship.
Thanks for the insight Ivan

Mapping composite poco to EF objectcontext entities

I have to produce an output from 3 separate tables(with a couple of fields from each table) into 1 output. I have a class that represents that output. The data is pulled from linq query of EF 6.1.x ObjectContext(Im stuck with using ObjectContext due to the nature of my clients needs....) entities (the 3 classes properly joined in the query) to a list of the new class (List<>). I populate a grid and all is fine. However the user wants to edit the data in the grid and now I need to push those new changes back.
My question is this: Can I map my new class back to the entities field to field? Or am I stuck with iterating through the collection and updating the tables individually? I thought I could map but I haven't run across anything that substantiates this.
Could you not do this using the "Proxy" pattern?
I've done a 2 entity + Wrapper example pseudo example below.
EF would "Save" the SuperWrapper.DeptProxy and the SuperWrapper.EmpProxy.
public partial class DepartmentEFEntity {
public virtual Guid? DepartmentUUID { get; set; }
public virtual string DepartmentName { get; set; }
public virtual ICollection<EmployeeEFEntity> Employees { get; set; }
}
public partial class EmployeeEFEntity
{
public virtual Guid? ParentDepartmentUUID { get; set; }
public virtual Guid? EmployeeUUID { get; set; }
public virtual DepartmentEFEntity ParentDepartment { get; set; }
public virtual string SSN { get; set; }
}
public class SuperWrapper
{
internal DepartmentEFEntity DeptProxy { get; private set; }
internal EmployeeEFEntity EmpProxy { get; private set; }
public SuperWrapper(DepartmentEFEntity dept, EmployeeEFEntity emp)
{
this.DeptProxy = dept;
this.EmpProxy = emp;
}
public string DepartmentName
{
get { return null == this.DeptProxy ? string.Empty : this.DeptProxy.DepartmentName; }
set { if(null!=this.DeptProxy{this.DeptProxy.DepartmentName =value;}}
}
public string EmployeeSSN
{
get { return null == this.EmpProxy ? string.Empty : this.EmpProxy.SSN; }
set { if(null!=this.EmpProxy{this.EmpProxy.SSN =value;}}
}
}

Categories