i am using this in my data layer
public static IQueryable<Permission> ListAll()
{
using (InventorySystemEntities context = new InventorySystemEntities(new ConfigurationManager().ConnectionString))
{
IQueryable<Permission> result = context.Permissions;
return result;
}
}
it should put all rows inside the result variable. however doing something like this, and it will result to context has been disposed..
permissionList = PermissionModel.ListAll();
chkListGeneral.DataSource = permissionList.Where(p => p.Parent == "General");
is there a way to filter the IQueryable without a context?
The connection is accessible only as long as the context that wraps it. Your method returns IQueryable, so the filter is trying to be "translated" to a DB query, but the underlying query provider no longer exists. You either need to specify the where condition while the context still exists, or force eager load (e.g. by calling ToList() on the result variable), return IEnumerable and filter the results in memory.
Related
In a simple web API call to receive some data, I set db.Configuration.LazyLoadingEnabled = false;. Then I retrieve elements from the database via Entity Framework. These are converted into an exchange object using an explicit cast. This exchange class in turn contains conversions using an explicit cast again. Now I would like to know within such a cast method whether lazy loading is active or not, without knowledge of the actual database context. Is there a way to determine this using only the proxy object?
The reason is that I would like to set a list of child elements in my exchange object to NULL if it was not loaded in the proxy object. However (according to my observation) the lists are simply created empty with zero child elements. As a result, I cannot see exactly whether there are actually no assigned children in the database, or whether the data has not been loaded at all. Is there a reliable way to find this out?
public async Task<IEnumerable<Models.DataExchange.Plant>> GetPlantsWithStorages() {
db.Configuration.LazyLoadingEnabled = false;
// Get list from database
List<Models.Plant> plantList = await db.Plants
.IncludeOptimized(plant => plant.PlantAreas)
.IncludeOptimized(plant => plant.PlantAreas.Select(plantArea => plantArea.Storages))
.IncludeOptimized(plant => plant.PlantAreas.Select(plantArea => plantArea.LoadingBays))
.OrderBy(plant => plant.Name)
.ToListAsync();
// Cast and return result to client
return plantList.Select(p => (Models.DataExchange.Plant)p);
}
public static explicit operator StorageLocation(Storage storage) {
if (storage == null)
throw new ArgumentNullException(nameof(storage));
// storage.ChargeCarrier_Storage won't be filled in my example.
// However, the list is not null, but an empty list.
// Is there something like storage.ChargeCarrier_Storage.IsLoaded?
return new StorageLocation() {
Description1 = storage.Description1,
Description2 = storage.Description2,
ID_Storage = storage.ID,
ID_StorageType = storage.ID_StorageType,
ChargeCarriers = storage.ChargeCarrier_Storage?.Select(ccs => (ChargeCarrier)ccs.ChargeCarrier)
};
}
without knowledge of the actual database context. Is there a way to determine this using only the proxy object?
You can examine the runtime type of the entity. It will be a proxy type, from a dynamic assembly, isntead of an Entity type from the Assembly that defines your Entities. Eg
bool IsProxy(object entity)
{
return System.Reflection.Assembly.GetExecutingAssembly() != entity.GetType().Assembly;
}
I cannot see exactly whether there are actually no assigned children in the database, or whether the data has not been loaded at all. Is there a reliable way to find this out?
The right way to do that is through the DbContext. eg
var areasLoaded = db.Entry(plant).Reference(a => a.PlantAreas).IsLoaded();
Suppose I have built up, through some conditional logic over many steps, an IQueryable<T> instance we'll call query.
I want to get a count of total records and a page of data, so I want to call query.CountAsync() and query.Skip(0).Take(10).ToListAsync(). I cannot call these in succession, because a race condition occurs where they both try to run a query on the same DbContext at the same time. This is not allowed:
"A second operation started on this context before a previous asynchronous operation completed. Use 'await' to ensure that any asynchronous operations have completed before calling another method on this context. Any instance members are not guaranteed to be thread safe."
I do not want to 'await' the first before even starting the second. I want to fire off both queries as soon as possible. The only way to do this is to run them from separate DbContexts. It seems ridiculous that I might have to build the entire query (or 2, or 3) side-by-side starting with different instances of DbSet. Is there any way to clone or alter an IQueryable<T> (not necessarily that interface, but it's underlying implementation) such that I can have one copy that runs on DbContext "A", and another that will run on DbContext "B", so that both queries can be executing simultaneously? I'm just trying to avoid recomposing the query X times from scratch just to run it on X contexts.
There is no standard way of doing that. The problem is that EF6 query expression trees contain constant nodes holding ObjectQuery instances which are bound to the DbContext (actually the underlying ObjectContext) used when creating the query. Also there is a runtime check before executing the query if there are such expressions bound to a different context than the one executing the query.
The only idea that comes in my mind is to process the query expression tree with ExpressionVisitor and replace these ObjectQuery instances with new ones bound to the new context.
Here is a possible implementation of the aforementioned idea:
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Linq.Expressions;
namespace System.Data.Entity
{
public static class DbQueryExtensions
{
public static IQueryable<T> BindTo<T>(this IQueryable<T> source, DbContext target)
{
var binder = new DbContextBinder(target);
var expression = binder.Visit(source.Expression);
var provider = binder.TargetProvider;
return provider != null ? provider.CreateQuery<T>(expression) : source;
}
class DbContextBinder : ExpressionVisitor
{
ObjectContext targetObjectContext;
public IQueryProvider TargetProvider { get; private set; }
public DbContextBinder(DbContext target)
{
targetObjectContext = ((IObjectContextAdapter)target).ObjectContext;
}
protected override Expression VisitConstant(ConstantExpression node)
{
if (node.Value is ObjectQuery objectQuery && objectQuery.Context != targetObjectContext)
return Expression.Constant(CreateObjectQuery((dynamic)objectQuery));
return base.VisitConstant(node);
}
ObjectQuery<T> CreateObjectQuery<T>(ObjectQuery<T> source)
{
var parameters = source.Parameters
.Select(p => new ObjectParameter(p.Name, p.ParameterType) { Value = p.Value })
.ToArray();
var query = targetObjectContext.CreateQuery<T>(source.CommandText, parameters);
query.MergeOption = source.MergeOption;
query.Streaming = source.Streaming;
query.EnablePlanCaching = source.EnablePlanCaching;
if (TargetProvider == null)
TargetProvider = ((IQueryable)query).Provider;
return query;
}
}
}
}
One difference with the standard EF6 LINQ queries is that this produces ObjectQuery<T> rather than DbQuery<T>, although except that ToString() does not return the generated SQL, I haven't noticed any difference in the further query building / execution. It seems to work, but use it with care and on your own risk.
You could write a function to build up your query, taking DbContext as a parameter.
public IQueryable<T> MyQuery(DbContext<T> db)
{
return db.Table
.Where(p => p.reallycomplex)
....
...
.OrderBy(p => p.manythings);
}
I've done this many times and it works well.
Now it's easy to make queries with two different contexts:
IQueryable<T> q1 = MyQuery(dbContext1);
IQueryable<T> q2 = MyQuery(dbContext2);
If your concern was the execution time taken to build the IQueryable objects, then my only suggestion is don't worry about it.
So you have an IQueryable<T> that will be performed on DbContext A as soon as the query is executed and you want the same query to run on DbContext B when the query is executed.
For this you'll have to understand the difference between an IEnumerable<T> and an IQueryable<T>.
An IEnumerable<T> holds all code to enumerate over the elements that the enumerable represents. The enumeration starts when GetEnumerator and MoveNext are called. This can be done explicitly. However it is usually done implicitly by functions like foreach, ToList, FirstOrDefault, etc.
An IQueryable does not hold the code to enumerate, it holds an Expression and a Provider. The Provider knows who will execute the query, and it knows how to translate the Expression into the language that is understood by the query executioner.
Due to this separation, it is possible to let the same Expression be executed by different data sources. They don't even have to be of the same type: one data source can be a database management system that understands SQL, the other one could be a comma separated file.
As long as you concatenate Linq statements that return an IQueryable, the query is not executed, only the Expression is changed.
As soon as enumeration starts, either by calling GetEnumerator / MoveNext, or by using foreach or one of the LINQ functions that do not return an IQueryable, the Provider will translate the Expression into the language the the data source understands and communicates with the data source to execute the query. The result of the query is an IEnumerable, which can be enumerated as if all data was in local code.
Some Providers are smart and use some buffering, so that not all data is transferred to local memory, but only part of the data. New data is queried when needed. So if you do a foreach in a database with a zillion elements, only the first few (thousands) elements are queried. More data is queried if your foreach runs out of fetched data.
So you already have one IQueryable<T>, therefore you have an Expression a Provider and an ElementType. You want the same Expression / ElementType to be executed by a differentProvider. You even want to change theExpression` slightly before you execute it.
Therefore you need to be able to create an object that implements IQueryable<T> and you want to be able to set the Expression, ElementType and a Provider
class MyQueryable<T> : IQueryable<T>
{
public type ElementType {get; set;}
public Expression Expression {get; set;}
public Provider Provider {get; set;}
}
IQueryable<T> queryOnDbContextA= dbCotextA ...
IQueryable<T> setInDbContextB = dbContextB.Set<T>();
IQueryable<T> queryOnDbContextB = new MyQueryable<T>()
{
ElementType = queryOnDbContextA.ElementType,
Expression = queryOnDbContextB.Expression,
Provider = setInDbContextB.Provider,
}
If desired you can adjust the query on the other context before executing it:
var getPageOnContextB = queryOnDbContextB
.Skip(...)
.Take(...);
Both queries are still not executed yet. Execute them:
var countA = await queryOnContextA.CountAsync();
var fetchedPageContextB = await getPageOnContextB.ToListAsync();
I'm trying to create app that implements MVP pattern using WinForms.
Wherein I'm also using EF+CodeFirst+Linq.
On the VIEW there is DataGridView control, that need filling a data. The VIEW call a method SELECT() of PRESENTER class, which in turn call a method SELECT() of MODEL class.
How to transfer the data from Data Base to VIEW via PRESENTER?
I'm trying to use return but it not work because i'm using the USING block.
internal void Select()
{
using (GoodsContext context = new GoodsContext())
{
var items = from Items in context.Goods
select Items;
}
}
Quite interesting question. Of course one can materialize the query and return it as IEnumerable, but I was wondering what is the way to return it as IQueryable, to allow further filtering/sorting etc. The only way I see is to not dispose the DbContext (apparently the returned queryable keeps reference to it), but is it safe? Then I've googled and found this Do I always have to call Dispose() on my DbContext objects? Nope. The explanation inside sounds reasonable to me, and we already have a disposable object (Task) that we are not supposed to Dispose.
Shortly, you can remove the using statement and return the IQueryable.
Change return type of Select method to List<Good>
Then "materialize" result to the List of data, and you will not depend on the DataContext
internal List<Good> Select()
{
using (GoodsContext context = new GoodsContext())
{
return context.Goods.Select(items => items).ToList();
}
}
You should change type of method Select from void to IEnumerable<Good> to be able to return something. Also use .ToList to materialize result to a List:
internal IEnumerable<Good> Select()
{
using (GoodsContext context = new GoodsContext())
{
var items = (from Items in context.Goods
select Items).ToList();
return items;
}
}
In my UserRepository I have a GetActive method:
public IEnumerable<User> GetActive()
{
var users = context.Set<UserTbl>().Where(x => x.IsActive);
foreach(var user in users)
{
yield return entityMapper.CreateFrom(user);
}
}
The entityMapper is used to map from an EF-generated UserTbl to the User domain entity.
There exists thousands of users so I want the GetActive method to defer execution while returning the IEnumerable<User> so that the entire list isn't pulled unnecessarily. I have done that above with the foreach and yield.
When testing, it seems that the all the data is being fetched regardless. The following two calls take the same time:
// Get only 5 users in memory
var someUsers = UserRepository.GetActive().Take(5).ToList();
// Get all 100,000 users into memory
var allUsers = UserRepository.GetActive().ToList();
What am I doing wrong?
The moment you use foreach, the data is enumerated. You have to use IQueryable only until the ToList method. Your idea about deferring data using IEnumerable seem nice, but it is wrong. IEnumerable always returns all data, it just doesn't force the provider of the data to hold it all in memory. You have to use IQueryable if you want to provider to return pieces of data. But then, you can't use foreach and yield, because it always enumerates all data in it's parameter.
Only way to do what you want is to pass the required query into the GetActive method.
public IEnumerable<User> GetActive(Func<IQueryable<User>, IQueryable<User>> modifier)
{
var users = modifier(context.Set<UserTbl>().Where(x => x.IsActive));
foreach(var user in users)
{
yield return entityMapper.CreateFrom(user);
}
}
// Get only 5 users in memory
var someUsers = UserRepository.GetActive(q=>q.Take(5)).ToList();
// Get all 100,000 users into memory
var allUsers = UserRepository.GetActive(q=>q).ToList();
But I would really recommend not having repositories in your architecture at all. They introduce needless complexity over already complex ORM. See more in Repository pattern with Entity framework
I use asp.net and EF 4 in C#.
I have a DetailsView with associated a ObjectDataSource.
<asp:ObjectDataSource ID="uxEntityDataSourceAuthors" runat="server"
SelectMethod="GetAuthors"
TypeName="WebProject.Web.Cms.AdminCms.Sections.CmsContents.ContentInformation">
</asp:ObjectDataSource>
This the code for the Method:
public IEnumerable<CmsAuthor> GetAuthors()
{
if (Roles.IsUserInRole("CMS-AUTHOR"))
{
using (CmsConnectionStringEntityDataModel context = new CmsConnectionStringEntityDataModel())
{
// Display all Authors for specific logged-in User.
// Get Guid for current logged-in User.
MembershipUser myLoggedinUser = Membership.GetUser();
Guid myUserGuid = (Guid)myLoggedinUser.ProviderUserKey;
// Get list of Authors filtering my current logged-in User.
var myAuthorsForAuthor = from a in context.CmsAuthors
where a.UserId == myUserGuid
orderby a.LastName ascending
select a;
return myAuthorsForAuthor.AsEnumerable();
}
}
return null;
}
When I'm running the code I receive this error:
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
Any idea what I'm doing wrong and how to fix it?
You're closing the CmsConnectionStringEntityDataModel called context before getting the data. Remember that AsEnumerable() will return a lazy enumerator, no data has been read from the source when you return and dispose of `context.
Use ToArray() (or ToList()) to ensure you get the data into memory before closing the source.
Calling AsEnumerable does not enumerate the collection it just changes it from IQeuryable<T> to IEnumerble<T>. You are disposing of the ObjectContext before the data is fetched from the database. Use ToList() which will enumerate the collection and fetch the data.