Entity Framework TPT inheritance - How to get from database? - entity-framework

I have a BaseTable with TypeId column which is foreign key to Type table. I mapped this into entity framework model by using template per hierarchy pattern.
Now i have a BaseClass and two subclasses named SubClass1 and SubClass2 and make BaseClass abstract.
From one of my page to second page i get an id (which is an id of BaseClass of course) and i want to get this object from database.
How i will make my query? Coming id is owned by an Subclass of course.
For example, can i write like this:
BaseClass object = provider.getfrombaseclassbyid(id);
Can i make a boxing like this? if can, how can i know what is object is really. It is a Subclass1 or Subclass2? How can i know it?
Can you help me what should i do?

I am not sure if the following answers your question, but you can indeed query on a set that respresents abstract entities:
BaseClass entity = context.BaseClasses.SingleOrDefault(b => b.Id == id);
Of course the result will never be of type BaseClass because no instance of an abstract type can be created. It will either be of type SubClass1 or SubClass2 (or null if an entity with that id doesn't exist). Entity Framework can decide which type has to be used when the object is created by looking either at the value of the discriminator column (for Table-Per-Hierarchy (TPH) inhericance) or by joining from the base table into the tables of the derived types (for Table-Per-Type (TPT) inheritance).
You can check the materialized type for example by using:
string typeName = entity.GetType().Name; // will be "Subclass1" or "Subclass2"
Or:
if (entity is SubClass1)
// ...
else if (entity is SubClass2)
// ...
If you know in advance that you want to load an entity of type SubClass1 you can use the OfType<T> operator:
SubClass1 entity = context.BaseClasses.OfType<SubClass1>()
.SingleOrDefault(b => b.Id == id);
If the entity with the given id is not a SubClass1 but a SubClass2 instead, the result of this query will be null. Otherwise it is guaranteed to be a SubClass1.

Related

Is it possible to include Core Data entity type in constraint?

I'm working with Core Data + Swift 4.2 + Xcode 10. In my data model, I have an abstract entity A which has no parent entity, entity B which has A as its parent, and C which has A as its parent.
Entity A has a timestamp field, which is therefore inherited by B and C. I would like to impose a constraint that timestamp must be unique within an entity type. That is, I want all B items to have unique timestamps, and all C items to have unique timestamps, but some B item might have the same timestamp as some C item.
Is there a way to express that constraint in Xcode? The "Constraints" field in the entity editor wants a list of attributes. Timestamp is an attribute, so that's OK, but the entity type (B or C) is not. So I don't see a way to include entity type.
Is it possible that entity type is an implicit attribute? Just a shot in the dark here.
EDIT: To be clear, the reason I'm asking is that I tried to save an instance of B with timestamp T1 and an instance of C with timestamp T1 also, and I got an error to the effect that the constraint was violated. I was hoping that both instances would be saved (perhaps that was wishful thinking on my part). I am working with the Sqlite backend if that makes a difference.
I don't think you can specify this behavior automatically in Core Data. But you can achieve this by adding another property to Entity A, and then making a constraint on the combination of that property and timestamp.
In this example, I added subtype to Entity A, and specified a constraint of subtype,timestamp.
These are the entity classes:
class EntityA: NSManagedObject {
#NSManaged var timestamp: String
#NSManaged var subtype: String
}
class EntityB: EntityA { }
class EntityC: EntityA { }
You need to set the subtype correctly before saving the entity:
entity.subtype = "B"
or
entity.subtype = "C"
or more generically:
entity.subtype = entity.entity.name!
It's not beautiful, but it works.
I just tried to do something similar. I ended up being able to do a switch statement with the property, and then use case is Entity:
switch variableEntity {
case is EntityA:
print("EntityA:")
default:
print("Default:")
}

Fluent NHibernate Create entity mapping for overlapping entities

For eg. I have two tables in my database
NonResidentStudents - columns studentID, studentname, ModeOfTransport
ResidentStudents - columns studentID, studentname, DateOfJoiningHostel
studentID and studentName are common columns and the last column is uncommon between the two
For some reason, I cant change these tables or define a common master table and make uncommon columns in sub tables. So the table stucture is rigid.
Now when trying to create an entity and mapping for the above schema using FLUENT NHIBERNATE (only) I would like to know if I can define some sort of a common entity and common mapping for the common columns and create child entities inheriting from the common entities. In the child entity and mapping class I will have representations for the uncommon columns. Could anyone please share code of how to do it.
I did this before.
Common Class
public class BaseMapping : ClassMap<EntityBase>{
public BaseMapping ()
{
UseUnionSubclassForInheritanceMapping ();
// All the rest of the mapping attributes
}
}
For your individual classes that will inherit from the base you do this:
public class DepartmentMapping : SubclassMap<Department>
{
public DepartmentMapping ()
{
Abstract ();
// Map all the unique attributes
}
}
The code above will create one class based on Department and EntityBase. It will not create a table called EntityBase.

Entity Framework atypical 1-[0..1] -- model-only Association -- EF LINQ select possibilities

Suppose the following tables
ParentEntities
ParentID
ChildEntities
ChildID
ParentID
These tables do not have a FK defined in the schema.
In EF designer, after generating from DB, I add an association:
- Parent Multiplicity: 1
- Child Multiplicity: 0 or 1
When I build, I get the error: "Error 3027: No mapping specified for the following EntitySet/AssociationSet - ParentChild"
But if I try to configure table mapping for the association like this..
Maps to ChildEntities
Parent
ParentID <-> ParentID (parent entity prop <-> child table column)
Child
ChildID <-> ChildID (child entity prop <-> child table column)
.. I get this: Error 3007: Problem in mapping fragments starting at lines xxx, xxx: Column(s) [ParentID] are being mapped in both fragments to different conceptual side properties.
Why this is an error doesn't make sense. Limitation of the current implementation?
[EDIT 1]
I'm able to make this work by creating a 1-N association. That's not ideal, but it works just the same, just have to add a read-only child property in a partial:
public partial class Parent
{
public Child Child { get { return Childs.Any() ? null : Childs.First(); } }
}
This seems like the best solution for me. I had to add a FK to the database to get EF to generate the association and navigation property, but once it was added I was able to remove the FK, and further updates to the model from the DB did not remove the association or Navigation properties.
[EDIT 2]
As I was investigating how to work around not caring about the association being modeled in EF, I ran into another issue. Instead of the read-only Child property I made it normal ..
public partial class Parent
{
public Child Child { get; set; }
}
.. but now I need a way to materialize that from the query:
var query = from parents in context.Parents
// pointless join given select
join child in context.Childs
on parents.ParentID equals child.ParentID
select parents;
I can select an anonymous type ..
// step 1
var query = from parents in context.Parents
join child in context.Childs
on parents.ParentID equals child.ParentID
select new { Parent = parents, Child = child };
.. but then I've got to consume more cycles getting that into my entity:
// step 2
var results = query.Select(x => {
var parent = x.Parent;
parent.Child = x.Child;
return parent; });
Is there a better/streamlined way to do this from the query select so the EF materializer can do it from the get-go? If not, then I'll resort to Edit 1 methodology ..
Ef Code first requires 1->0..1 relationships for the Child to have the same primary key.
Maybe this a similar restriction In the modeler in this circumstance.
ParentId (Key) required in Both tables.
I have never tried adding such relationships in designer afterwords in DB first.
EDIT: to match your EDIT2:
I would stay on the direction . Use Navigation properties to get from Join back to original class A and B.
query = context.Set<JoinTable>.Where(Jt=>Jt.NavA.Id == ClassAId
&& Jt.navB.Id == ClassBId)
use a select if your need entries returned from either ClassA or ClassB.

Entity Framework TPH - Additional WHERE clause only for one subtype

Suppose I have a class Parent, with two subclasses, AChild and BChild. I have these mapped to a single table using Entity Framework 5.0.0 on .NET 4.5, using TPH.
public abstract class Parent {
public string Type { get; set; } // Column with this name in DB is discriminator.
public string Status { get; set; }
}
public class AChild : Parent {
// Other stuff.
}
public class BChild : Parent {
// Other stuff.
}
The code to configure the mapping:
class ParentConfiguration : EntityTypeConfiguration<Parent> {
Map((EntityMappingConfiguration<AChild> mapping) => mapping
.Requires("Type")
.HasValue("A"));
Map((EntityMappingConfiguration<BChild> mapping) => mapping
.Requires("Type")
.HasValue("B"));
}
I have a need to run a query that returns both AChild and BChild objects. However, it needs to filter ONLY the AChild rows by a second column, which in this example I will call Status.
Ideally I would want to do the following:
public IList<Parent> RunQuery() {
IQueryable<Parent> query =
this.context.Set<Parent>()
.Where((Parent parent) => !parent.Type.Equals("A") || parent.Status.Equals("Foo"))
.OrderBy((Parent parent) => parent.Number);
return query.ToList();
}
This doesn't work. It insisted on looking for a "Type1" column instead of just letting both the discriminator and a "Type" property be mapped to the same "Type" column.
I know of the "OfType" extension method that can be used to completely filter down to one type, but that's too broad a brush in this case.
I could possibly run multiple queries and combine the results, but the actual system I'm building is doing paging, so if I need to pull back 10 rows, it gets messy (and inefficient) to query since I'll either end up pulling back too many rows, or not pull back enough and have to run extra queries.
Does anyone have any other thoughts?
There are few problems. First of all you cannot have discriminator mapped as a property. That is the reason why it is looking for Type1 column - your Type property results in second column because the first one is already mapped to .NET types of your classes. The only way to filter derived types is through OfType.
The query you want to build will be probably quite complex because you need to query for all Bs and concatenate them with result of query for filtered As. It will most probably not allow you to concatenate instances of Bs with As so you will have to convert them back to parent type.

EF4 inheritance and Stored procedures

I implemented inheritance with a discriminator field so all my records are in the same table. My basetype is Person (also the name of the table) and Driver and Passenger inherit from it. I receive instances of the correct type (Driver and Passenger) when I perform a query on the object context to Person. example:
var q = from d in ctx.Person
select d;
But I also create a function that calls a stored procedure and mapped the output of the function to the type Person. But now I get a list of Person and not Drivers or Passengers when I execute this method.
Anybody an idea how to solve this or is this a bug in EF4?
AFAIK, you can't use discriminator mapping (e.g TPH) when dealing with stored procedure mappings.
The stored procedure must be mapped to a complex type or custom entity (e.g POCO), the mapping cannot be conditional.
What you could do is map it to a regular POCO, but then project that result set into the relevant derived type (manual discrimination).
E.g:
public ICollection<Person> GetPeople()
{
var results = ExecuteFunction<Person>(); // result is ObjectResult<Person>
ICollection<Person> people = new List<Person>();
foreach (var result in results)
{
if (result.FieldWhichIsYourDiscriminator == discriminatorForDriver)
{
people.Add((Driver)result);
}
// other discriminators
}
}
If your always expecting a collection of one type (e.g only Drivers), then you wouldn't need the foreach loop, you could just add the range. The above is in case you are expecting a mixed bag of different people types.
Would be interested to see other answers, and if there is a better way though - but the above should work.