I have a class called MenuContainer
public partial class MenuContainer : IEquatable <MenuContainer>
{
[Column("Id ")]
[Key]
public int Id { get; set; }
public int MenuId { get; set; }
public int WareId { get; set; }
public int Price { get; set; }
public virtual Menu Menu { get; set; }
public virtual Ware Ware { get; set; }
public bool Equals(MenuContainer other)
{
return (this.Id == other.Id && this.MenuId == other.MenuId && this.WareId == other.WareId);
}
}
and it has relation with Menu (every menu can have multi menuContainer).
Now when i want to load MenuContainer with relation i can use Include(). Like:
context.MenuContainers.Include("Menu").Include("Ware.WareCategory").Include("Ware.WareDescriptions.Description");
But my problem is that entity framework generate long script for this
(about 2000 line code of script and nested select and join)
so i decide to write custom procedure sth like this:(not what i want but simple one)
SELECT
mc.MENU_CONTAINER_ID AS Id,
mc.MENU_ID AS MenuId ,
mc.WARE_ID AS WareId,
mc.WARE_PRICE_IN AS Price,
mc.WARE_PRICE2_IN AS Price2,
m.MENU_NAME_VC AS Name,
m.MENU_DESCRIPTION_VC AS [Description]
FROM dbo.MENU_CONTAINER mc
INNER JOIN dbo.MENU m ON m.MENU_ID = mc.MENU_ID
but how can i convert the output of my script to MenuContainer class???
(you know i should create MenuContainer and its relation "Menu" with output of this script)
I don't want to declare class, same as the output of my script and use sth
like
return this.Database.SqlQuery<CustomClass>(
"exec dbo.CustomeProcedure").ToList();
and fill CustomClass and then perform a lot of foreach and groupby and ...
to generate my MenuContainer class with its relation classes
what should i do?
how EF handle this issue?
Finally I found that if I want to write custom procedure I should have a class same as the out put so I create a class and fill it with my custom procedure like this :
this.Database.SqlQuery<CustomClass>("exec dbo.CustomeProcedure").ToList();
But in this case as I mentioned, I had to perform foreach and .... to extract
my classes and its property (like list of another entity). It takes time to write but
the execution time improved significantly.
In previous case when I used EF include() it takes about 2000 ms
but now it takes about 300 ms with all foreach and convert that i have done...
And I think EF does the same ( I mean convert out put of sp to class) at one of its layers.
Related
Hi my Entity is ParameterDetail as follows:
public class ParameterDetail
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
[NotMapped]
public string Description { get; set; }
//..other columns removed for brevity
public int LookupValueId { get; set; }
}
I call my stored procedure and load the results as follows...
List<ParameterDetail> paramDetails = this.ParameterDetails.FromSqlRaw("EXEC dbo.GE_GetStartParameter #GuidelineName={0}", guidelineName).ToList();
Now this all is working fine but now I have to call a slightly different procedure which does not have LookupValueId..
List<ParameterDetail> paramDetails =this.ParameterDetails.FromSqlRaw("EXEC dbo.GetParameterDetails #ParameterId={0}", nextParam).ToList();
I don't want to add another EntityModel just for this one column....
Can i use Mapped property (Data Annotation) at runtime somehow? Or could there be any other solution?
Can i use Mapped property (Data Annotation) at runtime somehow? Or could there be any other solution?
Not if you want EF to perform the mapping, at least not a good one. You can't change the attributes at runtime, but if you use Fluent configuration you could have two different DbContext subtypes that configure the same entity class differently. But that's not a very elegant solution.
You can always just execute the stored procedure with ADO.NET and map the data however you want.
In Entity Framework 6, given class A and derived class B: A, I would like to load entities A into instances of B without having to code for each property.
So given:
public class A
{
public Guid AId { get; set; }
public string Value { get; set; }
}
public class B: A
{
[NotMapped]
public string OtherValue { get; set; }
}
public MyDbContext: DbContext
{
public DbSet<A> As { get; set; }
}
I would like to:
using (MyDbContext db = new MyDbContext())
{
IEnumerable<B> Bs = db.As.LoadBsSomehow()
}
I'm guessing I could add DbSet<B> Bs { get; set; } and then in OnModelCreate I could override the table name to As perhaps. I'd like to avoid that if I can.
The purpose of doing this is that we need view models that need the underlying model plus some other properties and I don't want to mess up the models with all the different view model properties. This would simplify coding and maintenance for when the main model is changed -- the inheritance would automatically handle the changes in the derived class (view models).
I can then set the additional properties of the Bs in a Select or other method.
Also, I do NOT want to use reflection. I can code that up if I need it. I'd rather find out if EF 6 has the ability to do this natively.
UPDATE: I can do DbContext.Database.SqlQuery<T>. I would prefer to be able to use LINQ instead of writing SQL. I have no problem writing SQL, but LINQ is much more maintainable from a code perspective. Perhaps if I can use LINQ to create an IQueryable<B> and get the SQL for it?
public partial class Table
{
public int TableId { get; set; }
public Nullable<int> Num { get; set; }
public int NbSeats { get; set; }
public Nullable<int> R_LocationId { get; set; }
public virtual ICollection<Availibility> Availibilities { get; set; }
public virtual R_Locations R_Locations { get; set; }
}
public partial class Availibility
{
public System.DateTime DayRes { get; set; }
public Nullable<bool> Available { get; set; }
public int TableId { get; set; }
public virtual Table Table { get; set; }
}
I would like to implement this request with entity Framework:
select *
from Tables join Availibilities
on Availibilities.TableId = Tables.TableId
where Availibilities.Available=1
One of the slower parts of fetching data from a database is the transport of the data from the DBMS to your local process. Hence you should not transport more values than you actually plan to use.
Your Table has zero or more Availabilities. Your database implements this by giving the Availability table a foreign key to the Table that it belongs to.
So if you have a table with Id 4, which has 100 Availabilities, and you would query the Table with its Availabilities using a Join and Include you would transfer the foreign key Availability.TableId a 100 times, while you already know they will all have the value of Table.Id. You even know this value, because you asked for table with Id 4.
Hence, unless you plan to Update retrieved values, always use Select instead of querying complete classes.
Back to your question
Given a tableId, you want information of the table together with (some or all) its Availabilities.
Thanks to entity framework you don't have to use Join. If you use the collections, entity framework will do the join for you.
var tableWithAvailabilities = myDbContext.Tables
.Where(table => table.TableId == tableId)
.Select(table => new
{
// select only the properties you plan to use
Id = table.TableId,
Num = table.Num,
...
Availabilities = table.Availabilities
.Where(availability => ...) // if you don't want all Availabilities
.Select(availability => new
{
// again: select only the properties you plan to use
// not needed, you know it equals Table.TableId
// Id = availability.TableId,
Date = availability.DayRes,
Available = availability.Avialable,
})
.ToList(),
});
Entity framework knows which Join is needed for this. One of the nicer things when using the Collections instead of a Join is that you make your database more abstract: you really are thinking of a Table that has zero or more Availabilities. It is a shortage of a DBMS that it needs two tables to implement this. If your internal tables changes, for instance the name of the foreign key, your query does not change, because you don't use the foreign key
If you are not planning to update a fetched value, then it is seldom wise to fetch
There is two way to filter include Entity.
Using a projection (See #Harald answer)
Using a third party library
Disclaimer: I'm the owner of the project Entity Framework Plus
(
The EF+ Query IncludeFilter allow easily filter included entities. It works with EF6.x
return context.Tables
.IncludeFilter(x => x.Availibilities .Where(c => c.Available == 1))
.ToList();
Under the hood, the library does exactly a projection.
One limitation is all Include but now be called with IncludeFilter even if no filter is specified such as the account.
Wiki: EF+ Query Include Filter
I have a database first model.
My application UI provides a group of checkboxes, one for each value in Data_Type.
When the user checks one, I expect a row to be added in BUS_APPL_DATA_TYPE,
however I'm getting an error about Cannot insert explicit value for identity column in DATA_TYPE (And I absolutely do not actually want to insert data in this table)
My EF Model class for BUS_APPL has this property
public ICollection<BusApplDataType> BusApplDataType { get; set; }
And that EF Model class looks like
public partial class BusApplDataType
{
public int BusApplId { get; set; }
public int DataTypeId { get; set; }
[Newtonsoft.Json.JsonIgnore]
public BusAppl BusAppl { get; set; }
public DataType DataType { get; set; }
}
What exactly do I need to add to the BusApplDataType collection to get a record to be inserted in BUS_APPL_DATA_TYPE?
Edit:
At a breakpoint right before SaveChanges.
The item at index 2 is an existing one and causes no issues.
The item at index 3 is new. Without this everything updates fine. There is a DATA_TYPE with id 5 in the database.
The surrounding code, if it helps.
[HttpPut("{id}")]
public IActionResult Update(int id, [FromBody] BusAppl item)
{
...
var existing = _context.BusAppl.FirstOrDefault(t => t.Id == id);
...
existing.BusApplDataType = item.BusApplDataType; //A bunch of lines like this, only this one causes any issue.
...
_context.BusAppl.Update(existing);
_context.SaveChanges();
return new NoContentResult();
}
My issue was that I needed to use my context to look up the actual entity, using info passed, instead of using the one with all the same values that was passed into my api directly.
I'm using Entity Framework 4.3.1 Code First.
I have a pretty simple expression and entity model.
using (var PMCtx = new PMContext("PMEntities"))
{
var results =
PMCtx.Fetch<vwSDHOriginalMW>()
.Where(x => x.DT >= StartDate && x.DT < EndDate)
.ToList();
return results;
}
public class vwSDHOriginalMW : IEntityObject, IPMContext
{
public int Schedule { get; set; }
public DateTime DT { get; set; }
public int HE { get; set; }
public Decimal OrgMW { get; set; }
public Decimal DELIVERMW { get; set; }
public string NERCCode { get; set; }
public string NERCCodeStatus { get; set; }
public int SDHSDHID { get; set; }
}
This was taking 15 seconds every time, not just the first time. The model is mapped to a view in a Sql Server 2008 database. I output the query that EF was sending, and ran it in SSMS and it took a fraction of a second.
Why is this so slow in Entity Framework?
IEntityObject appears to be a marker interface so that the original programmer could be sure these were the only that get put into the generic.
EDIT 1
Fetch ends up going through some layer wrappers to get to the data layer where it does this:
private DbSet<TEntity> FetchSet<TEntity>()
where TEntity : class, IEntityObject
{
Type PassedType = typeof(TEntity);
if (!CheckedTypes.Any(x => x.FullName == PassedType.FullName))
if (!PassedType.GetInterfaces().Any(x => CtxInterfaces.Contains(x)))
throw new ArgumentException("Type passed is not a DbSet type of constructed context.");
else
CheckedTypes.Add(PassedType);
return privateContext.Set<TEntity>();
}
Cleaned up example of the query EF is sending
SELECT [Schedule],
[DT],
[HE],
[OrgMW],
[DELIVERMW],
[NERCCode],
[NERCCodeStatus],
[SDHSDHID],
[ScheduleDeliveryHourHistoryID]
FROM [vwSDHOriginalMW]
WHERE ([DT] >= '2/17/2013') AND ([DT] < '2/21/2013')
EDIT 2
The view in the database actually had one more column than my entity model had properties.
I added the property to the model.
public class vwSDHOriginalMW : IEntityObject, IPMContext
{
public int Schedule { get; set; }
public DateTime DT { get; set; }
public int HE { get; set; }
public Decimal OrgMW { get; set; }
public Decimal DELIVERMW { get; set; }
public string NERCCode { get; set; }
public string NERCCodeStatus { get; set; }
public int SDHSDHID { get; set; }
//missing property
public int ScheduleDeliveryHourHistoryID { get; set; }
}
After adding the property yesterday, it sped up tremendously for a while, ran in 4 seconds instead of 15. But today it's slow again, and nothing has changed.
UPDATE:
I have narrowed it down a little further. There are two methods that I can use that end up using the same FetchSet. The one that I am using returns an IQueryable instead of an IEnumerable. This seems normal, and since I am filtering afterward, most desirable. However the method that returns IQueryable takes 15 seconds while the IEnumerable takes less than a second. (I am calling ToList() on both) FetchAll turns out just to be a wrapper that calls Fetch and returns IEnumerable instead of IQueryable
public IQueryable<TEntity> Fetch<TEntity>() where TEntity : class, Common.IEntityObject
{
return privateContext.Fetch<TEntity>();
}
public IEnumerable<TEntity> FetchAll<TEntity>() where TEntity : class, Common.IEntityObject
{
return privateContext.FetchAll<TEntity>();
}
If I change
IEnumerable<vwSDHOriginalMW> results =
PMCtx.Fetch<vwSDHOriginalMW>()
.Where(x => x.DT >= StartDate && x.DT < EndDate)
.ToList();
to
IEnumerable<vwSDHOriginalMW> results =
PMCtx.Fetch<vwSDHOriginalMW>()
.ToList()
.Where(x => x.DT >= StartDate && x.DT < EndDate);
it is fast. But this isn't acceptable, because it seems like I would want my where clause to be passed to the database. In this case on a dev environment the view is only 180 rows, but it has potential to be millions, so I definitely don't want to return all my results into memory before I filter them.
After much digging and many headaches, I figured out that the view was referencing a view on a different database instance that referenced a table that was missing a non-clustered index. This caused the execution plan to get cached incorrectly. After adding the index on the other database:
USE [OTHERDATABASE]
GO
CREATE NONCLUSTERED INDEX [IX_ScheduleEnergyProfileJoin]
ON [dbo].[WTXS_ScheduleEnergyProfile] ([SEQSDR])
INCLUDE ([SEQSEPI],[StartDate],[EndDate])
GO
Then clearing the execution plan cache on the database with the view I'm using:
USE [MYDATABASE]
DBCC FREEPROCCACHE
DBCC DROPCLEANBUFFERS
The query is running quickly. So it turns out that the SQL that EF said it was using was probably not the sql that was getting sent to the database. Moral of the story is I should have gone through whatever hoops to get profiling permissions on this database instead of relying on the following to output the SQL that would actually be sent.
var sql = ((System.Data.Entity.Infrastructure.DbQuery<vwSDHOriginalMW>)results).ToString();