I have problem with EntityFramework querying. Suppose i have two entities: master and child. In child entity i have field (int)SNumber. Now i want query max number from childs:
labelMaxSNumber.text = (_context.Child.Select(s => s.SNumber)).Max();
This works normally on gui, but i want create this in DataModel:
labelMaxSNumber.text = _context.GetMaxSNumber();
I don't know where post this code: in ObjectContext partial class or in EntityObject partial class?
Yes it is possible. Simply create partial class for your context and add method:
public partial class YourContextName
{
public int GetMaxSNumber()
{
return this.Child.Max(c => c.SNumber);
}
}
Related
I am using EF Core 3.0 and have a requirement to change table name dynamically for which I am thinking to create an extensiion method.
Exact requirement:
I have two tables 'Sample' & 'Sample_History' and I want to acheive somthing like this:
To get records from 'Sample' table: DbContext.Samples.ToList();
To get records from 'Sample_History' table: DbContext.Samples.AsHistory().ToList();
Here, i want to dynamically change name of table from 'Sample' to 'Sample_History' using extension method 'AsHistory'. The obvious way is to get the SQL and change it which i want to aviod. Is there some way I can change entity in dbSet itself?
If i understand your requirement correct then you can try this:
public static class DbSetExtensions
{
public static DbSet<SampleHistory> AsHistory(this DbSet<Sample> sample)
{
return sample.GetService<DatabaseContext>().SampleHistory;
}
}
And for make your extension method generic:
public static class DbSetExtensions
{
public static DbSet<T> ToDbSet<T>(DbSet<Sample> dbSet) where T : class
{
return dbSet.GetService<DatabaseContext>().Set<T>();
}
}
I'm reviewing some code that was written in the EF 4 days because it stands out during performance benchmarking.
The purpose of the code is to materialize an ICollection<MyBaseClass> using Entity Framework (we're now on EF 6.1).
The code exists because references present in specific subclasses aren't materialized when retrieving
public Parent
{
public virtual ICollection<MyBaseClass>() Base { get; set; }
}
from the database, when the actual types stored are subclasses of MyBaseClass.
Example subclass:
public SubA : MyBaseClass
{
public virtual ICollection<Options> Ref1 { get; set; }
}
Currently, the code does something like this:
var parent = ctx.Parents.Include(p => p.Base).Where(...).Single();
LoadSubclasses(parent.Base);
...
private void LoadSubclasses(IEnumerable<MyBaseClass> myBase)
{
foreach (var my in myBase)
{
if (my is SubA)
{
this.Entry(my).Reference("Ref1").Load();
this.Entry((SubA)my).Ref1).Collection("Options").Load();
}
else... // Similar for other subclasses
}
}
Note that ICollection<MyBaseClass>() Base contains a mix of several concrete subclasses. There are generally a few hundred objects in the ICollection.
Is there a more efficient way to materialize Base?
It cannot be said in advance if the performance will be better (sometimes executing a single complex query, especially with sub collection includes may have actually negative impact), but you can minimize the number of database queries to K, where K is the number of subclass types that need additional includes.
You need to base the LoadSubclasses method on IQueryable<TBase> representing all base entities, and execute one query per each subclass type using OfType filter:
private void LoadSubclasses(IQueryable<MyBaseClass> baseQuery)
{
// SubA
baseQuery.OfType<SubA>()
.Include(x => x.Ref1.Options)
.Load();
// Similar for other subclasses
}
The usage with your sample would be:
var parent = ctx.Parents.Include(p => p.Base).Where(...).Single();
LoadSubclasses(ctx.Entry(parent).Collection(p => p.Base).Query());
or more generally:
var parentQuery = ctx.Parents.Where(...);
var parents = parentQuery.Include(p => p.Base).ToList();
LoadSubclasses(parentQuery.SelectMany(p => p.Base));
For those on EF Core 2.1 or later, this feature is now supported out-of-the-box.
Request from 2010:
When in an data model for entity framework has a navigation property
it is not posseble to eager load that navigation property besides when
using OfType<> or when eager loading the derived type itself by a
navigation property.
Response from 2018:
The feature is part of EF Core 2.1, which is currently in preview.
Please create issues in our issue tracker if you find any problems.
Is it possible to add summary properties(no database column) according LINQ from another property(column) in EF generated class from database and this property don't update(delete or remove from class) when update model from database(because this property(cloumn) is not on database)
Yes, it is. Classed generated by Entity Framework as an Entitied are always marked partial. It lets you extend the functionality with your own properties or method.
Let say your entity class is named Post. You can extend it with code like that:
public partial class Post
{
public int Average
{
get
{
return this.Items.Average();
}
}
}
Because it's not a part of designer-generated file it won't be overwritten when it's regenerated. However, there is one requirement to make it work: your custom part of Post class has to be in exactly the same namespace as code generated by EF.
Try using the [NotMapped] attribute on a property in a partial class. This will be ignored by Entity Framework.
public partial class EntityName
{
[NotMapped]
public int CalculatedProperty
{
get
{
return Numbers.Sum();
}
}
}
I have a base class and two derived classes.
Each of the derived classes implements the same type as a property - the only difference is the property name.
Sadly I don't have much influence on the class design -> they have been generated from a wsdl file.
I then have a property on the BaseType to encapsulate the common property. The plan was to use this property in my web views etc.
I have used the famous "Fruit-Example" to demonstrate the problem:
public class FruitBase
{
public virtual int ID { get; set; }
//
// The plan is to use this property in mvc view
//
[NotMapped]
public virtual FruitnessFactor Fruitness
{
get
{
if (this.GetType().BaseType == typeof(Apple))
return ((Apple)this).AppleFruitness;
else if (this.GetType().BaseType == typeof(Orange))
return ((Orange)this).OrangeFruitness;
else
return null;
}
}
}
public class FruitnessFactor { }
In my MVC controller, the following query works absolutely fine:
return View(context.FruitEntities
.OfType<Apple>().Include(a =>a.AppleFruitness)
.ToList());
But this one doesn't:
return View(context.FruitEntities
.OfType<Apple>().Include(a =>a.AppleFruitness)
.OfType<Orange>().Include(o => o.OrangeFruitness)
.ToList());
The error message I get is:
DbOfTypeExpression requires an expression argument with a polymorphic result type that is compatible with the type argument.
I am using EF 5.0 RC and the Code First approach.
Any help is much appreciated!
As far as I can tell you can't apply Include on multiple subtypes in a single database query. You can query one type (OfType<Apple>().Include(a => a.AppelFruitness)) and the same for another subtype. The problem is that you can't concat the results in the same query because the result collections have different generic types (apples and oranges).
One option would be to run two queries and copy the result collection into a new collection of the base type - as you already indicated in the comment section under your question.
The other option (which would only need a single query) is a projection. You would have to define a projection type (you could also project into an anonymous type)...
public class FruitViewModel
{
public FruitBase Fruit { get; set; }
public FruitnessFactor Factor { get; set; }
}
...and then can use the query:
List<FruitViewModel> fruitViewModels = context.FruitEntities
.OfType<Apple>()
.Select(a => new FruitViewModel
{
Fruit = a,
Factor = a.AppleFruitness
})
.Concat(context.FruitEntities
.OfType<Orange>()
.Select(o => new FruitViewModel
{
Fruit = o,
Factor = o.OrangeFruitness
}))
.ToList();
If you don't disable change tracking (by using AsNoTracking) the navigation properties get populated automatically when the entities get attached to the context ("Relationship fixup") which means that you can extract the fruits from the viewModel collection...
IEnumerable<FruitBase> fruits = fruitViewModels.Select(fv => fv.Fruit);
...and you'll get the fruits including the FruitnessFactor properties.
This code is pretty awkward but a direct approach without using a projection has been asked for several times without success:
bottleneck using entity framework inheritance
Entity Framework - Eager loading of subclass related objects
How do I deeply eager load an entity with a reference to an instance of a persistent base type (Entity Framework 4)
I'd like to know how to create a method that will allow me to generically do this...
public class Repo<T> : IGenericRepo<T> where T : class
{
protected PteDotNetEntities db;
public T Get(int id)
{
//how do I dynamically get to the correct entity object and select it by
//id?
}
}
Yes you can. If you know that all your entities will have simple primary key property of type int and name Id you can do simply this:
public interface IEntity
{
int Id { get; }
}
All your entities must implement this interface. Next you can simply do:
public class Repo<T> : IGenericRepo<T> where T : class, IEntity
{
protected PteDotNetEntities db;
public T Get(int id)
{
return db.CreateObjectSet<T>().FirstOrDefault(e => e.Id == id);
}
}
This is the simplest possible solution. There are better solutions using GetObjectByKey but they are more complex. The difference between FirstOrDefault and GetObjectByKey is repeatable execution. FirstOrDefault always executes DB query whereas GetObjectByKey first checks if the entity with the same key was already loaded / attached to the context and returns it without querying the database. As reference for version using GetObjectByKey you can check similar questions:
Entity Framework Simple Generic GetByID but has differents PK Name
Generic GetById for complex PK
You can simplify those examples if you know the name of the key property upfront (forced by the interface).
In case of using code first / DbContext API you can also check this question:
Generic repository EF4 CTP5 getById