MS EntityFramework: how to split entity with inheritance? - entity-framework

I have table name Transaction in the DB. I want to have 2 subclasses TransactionA and TransactionB. I've made it as described here: http://www.robbagby.com/entity-framework/entity-framework-modeling-table-per-hierarchy-inheritance/comment-page-1/#comment-607
As I use T4 templates I've generated self-tracking entities.
Everything is okay but one thing. I can see generated entities TransactionA and TransactionB but I cannot see them in the context object (ObjectContext). Is it normal? If so, how could I get TransactionB from the table using context if only Transaction class is accessible?
Thanks

This is as expected. Transaction A en B derive from the baseclass Transaction. In your entity model you can access them through the collection of Transactions like this:
Context context = new Context();
List<TransactionB> list = context.Transactions.OfType<TransactionB>().ToList();

Related

How to use a SQL query result as an object in Entity Framework?

I'm creating a data analysis process in c# using EF (code first). The data model involves about a dozen interrelated classes. Most of these directly correspond with tables in an existing database, but a couple key read-only object types are really the product of complex, multi-step SQL queries. I can't create a view or stored proc for the query.
I'd like to be able to use something like DbSet.SqlQuery() to load those query results into EF objects, and still leverage EF's ORM features to relate them with the rest of the object graph.
I think what I want is a way to override EF's SQL SELECT code when the DbSet tries to populate that query-based object from the database. Is this possible? Is there a better alternative approach?
Could you perhaps write your arbitrary query into a stored procedure? You could then use Entity framework to map that to a function.
I've found a way that's working for me, but it's hacky. (Is there a better way?)
Let's say Foo is a poco class that corresponds with an expensive query result that I want to explicitly write in SQL and use as an object in a read-only EF object graph. Foo includes foreign keys and navigation properties. My dbContext has a DbSet called Foos.
// Pre-req: prevent EF from trying to sync model with db, since Foos doesn't map to a db table.
public FooDbContext()
{
Database.SetInitializer<FooDbContext>(null);
}
// load the query data with SqlQuery() and Attach()
var foos = db.Foos.SqlQuery("<hand written SQL SELECT>", parameters);
foreach(var foo in foos) db.Foos.Attach(foo);
// Subsequently reference the data with .Local to prevent db hits (which would fail, since no Foo table in db.)
var result = db.Foos.Local.Select(...);
I do have to explicitly load related objects, but then all the relationship association happens automatically. For example let's say Bar has a 1-to-many with Foo, Foo has a BarId property (and a Bar navigation property) and maybe the Bar class has an observable collection of Foos. If Bars is stored as a db lookup table, I could just do db.Bars.Load(), or something more filtered like:
var barIds = db.Foos.Local.Select(f => f.BarId).Distinct().ToArray();
db.Bars.Where(b => barIds.Contains(b.barId)).Load();
Then I can use Foo.Bar or Bar.Foos and everything works.

DTO/POCO with Entity Framework

I'm using EF5 Model First. I don't really understand what are the auto-generated classes from the EDM. According to some documentation this classes are POCOs but why are they used in the context ?
Assuming I have a Student entity, then I get a Student POCO class and a DbSet StudentSet property in my context.
Will this next instructions put a POCO in my database ?
MyContext.StudentSet.Add(johndoe);
MyContext.SaveChanges();
So EF uses POCO to transfer data ? Actually I miss the step when POCO exchange data with entities or DTO and when the entities put data in the database.
The generated classes from the EDM is the ORM / Persistence classes. You use that classes to query / make changes from / to database. You need to translate any DTO object to POCO object when about making changes to database.
ORM is about mapping object to data in database, instead of dealing with insert into syntax to insert record to database in the application, you use StudentSet.Add to add a new data. The johndoe information will be translated into sql syntax, EF will map each property to each column when translating it into query.
The Add method will store the johndoe information as Added in the memory but it will not be executed right away to the database. If you have another Add method, it will be marked as Added too. The moment you call SaveChanges, all the changes will be saved into database by sending a generated query.
The mapping between DTO and EF entity happens before you add the johndoe. You might have another DTO class that is used in the UI. You need to map it manually or using mapper library to create a POCO object from a DTO object. For example:
// studentDto as parameter
var johndoe = new Student
{
Name = studentDto.StudentName,
Age = studentDto.StudentAge
};
MyContext.StudentSet.Add(johndoe);
// studentDto might have another information as well
var johndoeSubject = new Subject
{
Name = studentDto.SubjectName,
Years = studentDto.SubjectYears
};
MyContext.SubjectSet.Add(johndoeSubject);
MyContext.SaveChanges();

Entity Framework : map duplicate tables to single entity at runtime?

I have a legacy database with a particular table -- I will call it ItemTable -- that can have billions of rows of data. To overcome database restrictions, we have decided to split the table into "silos" whenever the number of rows reaches 100,000,000. So, ItemTable will exist, then a procedure will run in the middle of the night to check the number of rows. If numberOfRows is > 100,000,000 then silo1_ItemTable will be created. Any Items added to the database from now on will be added to silo1_ItemTable (until it grows to big, then silo2_ItemTable will exist...)
ItemTable and silo1_ItemTable can be mapped to the same Item entity because the table structures are identical, but I am not sure how to set this mapping up at runtime, or how to specify the table name for my queries. All inserts should be added to the latest siloX_ItemTable, and all Reads should be from a specified siloX_ItemTable.
I have a separate siloTracker table that will give me the table name to insert/read the data from, but I am not sure how I can use this with entity framework...
Thoughts?
You could try to use the Entity Inheritance to get this. So you have a base class which has all the fields mapped to ItemTable and then you have descendant classes that inherit from ItemTable entity and is mapped to the silo tables in the db. Every time you create a new silo you create a new entity mapped to that silo table.
[Table("ItemTable")]
public class Item
{
//All the fields in the table goes here
}
[Table("silo1_ItemTable")]
public class Silo1Item : Item
{
}
[Table("silo2_ItemTable")]
public class Silo2Item : Item
{
}
You can find more information on this here
Other option is to create a view that creates a union of all those table and map your entity to that view.
As mentioned in my comment, to solve this problem I am using the SQLQuery method that is exposed by DBSet. Since all my item tables have the exact same schema, I can use the SQLQuery to define my own query and I can pass in the name of the table to the query. Tested on my system and it is working well.
See this link for an explanation of running raw queries with entity framework:
EF raw query documentation
If anyone has a better way to solve my question, please leave a comment.
[UPDATE]
I agree that stored procedures are also a great option, but for some reason my management is very resistant to make any changes to our database. It is easier for me (and our customers) to put the sql in code and acknowledge the fact that there is raw sql. At least I can hide it from the other layers rather easily.
[/UPDATE]
Possible solution for this problem may be using context initialization with DbCompiledModel param:
var builder = new DbModelBuilder(DbModelBuilderVersion.V6_0);
builder.Configurations.Add(new EntityTypeConfiguration<EntityName>());
builder.Entity<EntityName>().ToTable("TableNameDefinedInRuntime");
var dynamicContext = new MyDbContext(builder.Build(context.Database.Connection).Compile());
For some reason in EF6 it fails on second table request, but mapping inside context looks correct on the moment of execution.

Entity Framework Model First and Code First TPH issue

I'm facing two problems by trying to make a model first or code first using TPH concept.
The problem is that I need to use table per hierarchy at three levels, so that:
When I use Model First, the last hierarchy entity (third level) does not saves in database. I create an instance from this entity which inherits an abstract entity, which inherits another abstract entity. The data of two abstract entities are saved, but the last entity not saves. If the inheritance goes at maximum two levels works fine.
If I try to use Code First the problem is that I cannot share attributes with same name, for example: ClassB and ClassC has a property named "Name", and both inherits ClassA. When I map to generate database, I want to create only a sql table called ClassA, but it does not share the column "Name", it creates Name and Name1 columns.
I need to do one of this models works, otherwise I can't use inheritances in my model.
Hope some help!
Thanks

Entity framework: Database first/Code first hybrid

I am trying to create a custom Entity Framework (4.2) entity that would be mapped to my database like it would be done in a Code first approach.
The issue is that my entity framework data model is using Database first.
How can I add my custom entity to entity framework's context?
If by the Database first you mean that you already have EDMX created from exiting database you simply cannot use code first. You must create table and update model (EDMX) from the database to include it in EDMX.
Edit based on comment:
I want to create a BriefUser entity that would basically be a lighter
version of User but it would have properties retrieved from User's
foreign keys.
Well this is possible. You can either create BriefUser as common class and use projection in query.
var breifUser = (from x in context.Users
where ...
select new BriefUser
{
// Fill BreifUser's properties here
}).FirstOrDefault();
You can even refactor former code to reusable extension method:
public static IQueryable<BriefUser> ProjectUser(this IQueryable<User> query)
{
return query.Select(x => new BreifUser()
{ // Fill BreifUser's properties here });
}
and use it like:
var briefUser = context.Users.ProjectUser().FirstOrDefault(...);
It is also possible to define your new class as "entity view". The first problem is that each table can be mapped to only one entity (except some advanced concepts like inheritance or splitting) so you cannot define your BriefUser as a new entity type because mapping both User and BriefUser to UserTbl would violate this rule. You must use special construct called QueryView.
QueryView is view in mapping level. It allows you to create new mapped type which is projection of existing mapped entities defined directly in EDMX's MSL part. The projection is defined as custom Entity SQL query. The problem is that QueryView has limitations:
It doesn't offer all Entity SQL features - for example it doesn't support aggregations (which I consider as really missing feature). Without aggregations you for example cannot create a new type which will contain property counting some related entities.
It is not supported in designer. You must edit your EDMX as XML to define QueryView and you must write Entity SQL query yourselves.
Resulting type is a "view" and it is read-only.
I want to keep the EDMX file, but also be able to add an entity
(BriefUser) to EF's context.
This is not possible. Your BreifUser is only projection / view and EF is not able to track changes back to originating tables so you cannot add BreifUser to context and persist it. In case of QueryView you can achieve it if you define custom stored procedures which will no how to decompose BreifUser and modify all related tables. These stored procedures must be imported to the EDMX and mapped to data modification operations of the view entity. Btw. same will happen if you map your entity to the database view because EF takes all views as read-only.