Eager Loading an indirectly related table - asp.net-mvc-2

Im new to MVC, EF4 and Linq, so forgive my ignorance
If im using a Linq Query to return data to pop into a viewmodel, I can include tables with a relation and get to the data without relying on lazy loading.
However I have a problem eager loading data that isnt in a directly relatede table. e.g I have fixtures that relate to a season which in turn relates to a competition type. When querying the fixtures table with an include for season I can pass the list of fixtures into my viewmodel and can see the season being populated in the object:
var fixtures = (from f in predictorDB.Fixtures.Include("Season")
select f).ToList();
However, I have no idea how to pass along the competitionType as I need the title from it. If I look at the Season in a particluar fixture, the corresponding competitionType is null (but populated when lazy loading is on)
Thanks

Did you try something like this?
var fixtures = (from f in predictorDB.Fixtures.Include("Season.Competition")
select f).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.

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, Computed Entity Field

Is it possible to include a computed field in an EF entity? Example, lets say I have a shop selling products, and the products are grouped into categories.
When the list of categories is displayed for editing to the administrator of the shop I wish to list the number of products in each category as part of the list.
In NHibernate I would use a formula e.g.
<property name="Products" formula="dbo.Category_NumProducts(id)" />
I can't work out if something similar is possible for EF. I know I could make a category view and map this to a second entity but that seems wrong as its almost a complete duplication.
EDIT: If this isn't possible in EF, then what is the best way to accomplish this?
Unfortunately if your Category table doesn't have this as computed column you will not be able to map it without creating second entity - it leads to database view, defining query in EDMX or perhaps Query view in EDMX (but Query view may not work because you require aggregate function to be computed).
Edit:
IMHO the simplest solution (and also the best) is simply creating a ViewModel (some non mapped class) and use projection in Linq query:
var query = from c in context.Categories
where ...
select new CategoryView {
Id = c.Id,
Name = c.Name,
...
Products = c.Products.Count()
};

ADO.NET Entity Framework - How to select data from one Table only (and ignore other tables)?

Background is the team i'm in has just started using the EntityFramework; first we designed the database, put all the table relationships in place, foreign keys, etc; then thru visual studio add a new ADO.NET Entity Data Model, and auto-magically we get the generated edmx file representing the whole database !
Now i focus on two tables that provide data for all dropdowns and lookup lists;
TLookupDomain (domainID, domainName, domainDesc )
TLookup (lookupID, domainID, lookupCode, lookupDisplay, lookupDesc, sortOrder)
Relationship is 1-M going from left to right:
TLookupDomain -< TLookup -< TOther (+ another 30 or so other tables)
So lookupID is a foreign-Key to as many as 30 tables;
IQueryable<TLookup> qList = from l in ctx.TLookups
where l.domainID == 24
select l;
foreach (TLookup l in qList)
{
//do something.
System.Diagnostics.Debug.WriteLine("{0}\t{1}", l.lookupCode, l.lookupDisplay);
foreach (TOther f in l.TOthers)
{
System.Diagnostics.Debug.WriteLine("{0}\t{1}", f.feeAmount, f.feeDesc);
}
}
When i execute the above LINQ, i get all the fields for TLookup table (which is fair), BUT data is also fetched for the 30 or so tables that are linked to it, even though i am NOT interested in the other table's data at this point, and i am going to discard all data soon as LINQ fetches it.
Two Questions i have:
Q.1) Can i somehow modify the LINQ query above or tell the EntityFramework otherwise not to bother fetchin data from the 30 other linked tables ?
Q.2) is it "right" to have one edmx file that models the entire database? (sounds dodgy to me).
Configure Lazy Load to true for the model. Relations should be loaded only upon navegation. You can also split the models to avoid too many unnecessary relations.
Linq-to-Entities queries do not fetch anything automatically. Fetching of navigation properties is performet either by eager or lazy loading. You are not using eager loading because that requires calling Include in query (or ctx.LoadProperty separately). So if your data are fetched it must be due to lazy loading wich is enabled by default. Lazy loading triggers once you access the navigation property in the code.
You can also return only the data you need by using projections. Something like this should return readonly data:
var query = from l in ctx.TLookups
where l.domainId == 24
select new
{
l.lookupCode,
l.lookupDisplay,
l.TOthers
};
Having one or more EDMX is common dilemma. Working with single EDMX makes things more simple. If you want to know how to use multiple EDMXs and share conceptual definitions check these two articles: Part 1, Part 2.

Entity Framework: Exclude columns from the selection in Entity Framework?

I want to have an ObjectQuery that returns tracked entities (not static data), but I don't want it to load all the columns, I want some columns to load as null, I don't want to use select, since this will return an IEnumerable of the values, not tracked objects.
Is there a way to do it?
If yes, how do I then complete reloading those columns on demand?
Have you tried creating a view and then mapping the view?
By creating a view you can select the columns that you really want and only those will show up on the Entity Model.
I think the only way is to create new entity type which will not contain columns you don't need. You will map this entity type to the same table. On demand (lazy) loading works only for navigation properties.
Edit:
My previous idea doesn't work but in some special cases you can use idea from this article. Instead of modeling single entity from single table you will model multiple entities related with 1:1 relations. Entities will not overlap in properties (except the primary key) as my previous idea assumed because it doesn't work. You will than have main entity with fields you want to load immediately and related entities which will be lazy loaded when needed.