Use EF Code First Local extention - c#

The following method works properly in my service layer:
public override IList<City> GetAll()
{
var query = from item in _tEntities
select item;
query.Load();
return _tEntities.Local;
}
but when i try to run following method, the method returns old data loaded by GetAll() method.
public override IList<City> GetAll(Func<City, bool> predicate)
{
var query = from item in _tEntities
select item;
query.Where<City>(predicate);
query.Load();
return _tEntities.Local;
}
What is the problem and how can i fix them?
How can i use local method in this sample and reload new data into local(cache)?

You are looking at the wrong problem. What you are most likely seeing is a result of the fact that when you do the first query, the local cache is empty. So it only returns the results from your query. But when you do the second, it's returning the results of your first query AND your second query.
This comes down to the fact that you are using a shared DbContext between all your methods. Local contains a cache of all records the context has retrieved, not just the most recent query.
The correct solution is to not use Local in this manner. Even better, don't use a shared context since this can lead to context cache bloat.

I'm not too sure what you are trying to achieve with a .Load method here but it seems like you want the following.
public override IList<City> GetAll(Func<City, bool> predicate)
{
return _tEntities.Where<City>(predicate).ToList();
}

query.Where<City>(predicate);
This doesn't change query. The query.Load() on the next line ignores the predicate: you're calling query.Load() and not query.Where<City>(predicate).Load(). It's as if you had written
int i = 3;
i + 1;
Console.WriteLine(i); // still prints 3
In that example, C# does not really actually allow an addition to be used as a statement, but .Where(predicate) is a method call, and method calls can be used as such, even if they return values.
This is not your only issue (see the other answers), but my guess is that this issue is the one that leads to the unexpected results you're seeing.

Related

How to dynamically add query clauses while using Rally Api

I am using Rally Api to fetch some details, need to add more query clauses(.and) dynamically. Tried creating a string and then adding but parse error is what I am getting. Can some one help here?
editing
storyRequest.Query = new Query("LastUpdateDate", Query.Operator.GreaterThan, "2013-08-01");
Supposing I want to keep adding .and queries to the above one dynamically based on my inputs.
For instance I want the stories for different projects, iterations and releases and the user selects them.so in that case how will I add. I tried creating a string which will have and queries based on the input but am unable to append it to the earlier one. Any approach here would be useful.
Not sure whether you are looking for solution like this. Dont have enough reputation to comment. this is an example in java
//Inside Function start
public static QueryFilter q;
private static QueryFilter setDynamicQuery(String fieldName,String Operator,String fieldValue)
{
q=new QueryFilter(fieldName, Operator, fieldValue);
return q;
}
//Inside Function end
//When calling in main method start
QueryRequest existUserStoryRequest = new QueryRequest("HierarchicalRequirement");
String existStoryFormattedIDLst="US23456!US23457!US23446";
for(String StoryFormattedID:existStoryFormattedIDLst.split("!")){
existUserStoryRequest.setQueryFilter(setDynamicQuery("FormattedID", "=", StoryFormattedID));
}
//When calling in main method end

linq query that selects any object in the model

Edit
To understand what i am trying to do i will give an example
Suppose you used entity framework to generate multiple tables. Now you have MyDbEntities with objects (client, user, product, singer [attributes don't matter]). Now you create a method. This method gets an object as a parameter + MyDbEntities. The object would be a client, user, product, singer. In this method you have a query that given the object would return a list of that object. I am trying to create this method but i am still trying either with linq or sql but in vain so far
Update
I tried this, it works, but not the way i want it to. to understand me check the code below.
ViewBag.ok = LibMethods.get_all(MyDbEntities, "Client"); //Params = Entity & String
this how i can my method below is my method
public static Object get_all (MyDbEntitiesce, String given_entity_type)
{
if (given_entity_type.Equals("Client"))
{
var get_all = from clt in ce.Client
select clt;
return get_all.ToList().First();
}
else if (given_entity_type.Equals("Product"))
{
var get_all = from pdt in ce.Product
select pdt;
return get_all.ToList().First();
}
return null;
}
As you can see this method checks the object given and creates and returns a list of objects of that given_entity_type. here i return the first element just because i am doing this for tests.
now suppose that i add a new object to MyDbEntities & call it Developer i would have to update that method but i don't want to do that i want something generic that would work on any object i give it that exists in MyDbEntities. that's what i mean by generic/dynamic.
Would the OfType query be what you want? I'm not sure I clearly understand your question, but this query will filter the list of objects by the given type.
Although I do not understand what your ultimate goal is, I would suggest that you look into DbSet.Set() method:
You can then use it like this Context.Set<Singer>() or Context.Set<Client>() depending on your target table.
That is the most generic you can get. Try showing more Code to make your scenario more clear.

Strange exception in Linq-to-SQL

I developed the extension method:
public static IQueryable<T> Get<T>(this DataContext dataContext) where T : class
{
return dataContext.GetTable<T>();
}
Then I tried to use it:
dataContext.Get<XDbCurrency>().
Where(c => c.Id == XCurrencyId.USD).
SelectMany(
c =>
dataContext.Get<XDbCurrencyRate>().
Where(cr =>
cr.CurrencyId == c.Id &&
cr.StartOn <= DateTime.UtcNow &&
cr.EndOn > DateTime.UtcNow).
Take(1),
(c, cr) => cr).
ToArray();
I get the exception Member access 'XCurrencyId CurrencyId' of 'X.XDbCurrencyRate' not legal on type 'System.Data.Linq.Table``1[X.XDbCurrencyRate]. When I change Get back to GetTable - everything works! When I change the return type of Get from IQueryable<T> to Table<T> - it crashes.
UPDATE. I created XDataContextBase class, moved Get method there, inherited DBML-generated XDataContext from XDataContextBase - unfortunately it does not help. Magic!!
UPDATE. this.GetTable<XDbCurrencyRate> works, this.XDbCurrencyRates works, this.Get<XDbCurrencyRate> not works either Get is extension method or method in base class. By the way, internally this.XDbCurrencyRates is implemented absolutely like my Get. Magic!!
UPDATE. Looks like Linq-to-SQL supports only two things: either direct call of DataContext.GetTable<> or call of any-named property that returns System.Data.Linq.Table<XDbCurrencyRate>. If I create System.Data.Linq.Table<XDbCurrencyRate> Foo - it works, but when I create IQueryable<XDbCurrencyRate> Foo - it crashes with Queries with local collections are not supported.. Magic!!
Any ideas?
This is because the initial Get call is not part of the query tree. Just a normal method call. The second call is embedded in the tree and LINQ to SQL has no idea what that method means.
I know that EF would give up here immediately. I believe L2S is basically capable of running such a method locally and trying to inline the query that it returns. Here, that seems to now work out (or I'm wrong about that).
What I did was to create a custom LINQ provider that rewrites expression trees to execute such methods locally, inline their results into the query tree and then forward to LINQ to SQL. This is not trivial.
Maybe you can make AsExpandable from the so called "LINQ kit" (approximate spelling) work.

Often used LINQ returned from method

I have 1 LINQ which used so much. I try create the method which return this LINQ like:
public static System.Linq.Expressions.Expression<Func<MyEntity, bool>> GetFilteredEntity() {
return x => true/*Some condition*/;
}
public static Func<MyEntity, bool> GetFilteredEntity() {
return x => true/*Some condition*/;
}
And use this like
db.MyEntities.Where(GetFilteredEntity());
is successfull, But! I need use it like
db.ParentEntities.Where(entity => entity.MyEntities.Where(GetFilteredEntity()));
This code compiled too, but every time when i use it, i got the Error:
System.InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.
,even:
db.ParentEntities.Where(entity => entity.MyEntities.Where(GetFilteredEntity())).ToList();
throw this Exception too.
But,
db.ParentEntities.Where(entity => entity.MyEntities.Where(x => true/*Some condition*/))
still works fine!
So why it happend, and have some way to get round this?
Final working code
public static Expression<Func<MyEntity, bool>> GetFilteredEntity() {
return x => true/*Some condition*/;
}
and
var expression = GetFilteredEntity();
db.ParentEntities.Where(entity => entity.MyEntities.AsQueryable().Where(expression ));
Also .AsQueryable() thanks to Passing func as parameter in Linq to Entities and 'Internal .NET Framework Data Provider error 1025' error
In your first example the function is called and translated into an expression before it is even sent to the query provider. In the next two examples the function call is embedded within an expression that is sent to the query provider, and that query provider doesn't know what to do with that function call, so it just throws an exception. When you embed the actual expression in another expression, there is no function call to confuse the query provider.
As for a solution, just pull out the function call into a variable. The query provider is smart enough to see that you used a closed over variable, and will pull out its value. For a function call it's just not sure if it should evaluate it or try to translate it into something that should be done on the DB's end. Trying to do some of both would just be very confusing and hard to work with, both for the query provider, and for people using it. To simplify matters, function calls with expressions are never executed prior to sending the query. As for a closed over variable, there is no other way that it could be treated, so there isn't any other behavior to confuse it with.
var expression = GetFilteredEntity();
db.ParentEntities.Where(entity => entity.MyEntities.Where(expression ));
Looks like LazyLoading might be the culprit, have you tried popping the ToList() on the parameters?
db.ParentEntities.Where(entity => entity.MyEntities.Where(GetFilteredEntity()).ToList());

DataContext Accessed After Dispose

I'm using ASP.NET 4.0.
I've got the following code that returns with an error of "Cannot access a disposed object.
Object name: 'DataContext accessed after Dispose.'."
public IEnumerable<BatchHeader> GetHeaders()
{
using(NSFChecksDataContext context = DataContext)
{
IEnumerable<BatchHeader> headers = (from h in context.BatchHeaders
select h);
return headers;
}
}
If I change this to:
public IEnumerable<BatchHeader> GetHeaders()
{
using(NSFChecksDataContext context = DataContext)
{
return context.BatchHeaders.ToList();
}
}
It will work fine. I'm using this method to populate a RadGrid. Can anyone explain why the second method will work but not the first?
Thanks.
The first doesn't work because when the method returns the data context instantiated in the using block is disposed. However, the IEnumerable<BatchHeader> returned is lazily evaluated and needs this data context to be alive to enumerate its results.
You could do something like this:
public IEnumerable<BatchHeader> GetHeaders() {
using(NSFChecksDataContext context = DataContext) {
foreach(var header in context.BatchHeaders) {
yield return header;
}
}
}
The second block works because the query results are enumerated over and stored in memory before the data context is disposed of. After that happens, the data context isn't needed anymore. However, be careful when using code like your second block; if the BatchHeaders table is large you just pulled it all into memory.
Now, and here is the most serious part of my answer: I absolutely can't stand seeing queries that instantiate data contexts to execute. I want to know and control when my data contexts are being used.
I'm guessing the IEnumerable from your context is using deferred execution, so unless you force it to enumerate using ToList it doesn't do so until you use the values, which in this case is outside of the using block so the object will be disposed.
return headers.AsEnumerable();
should work, because by default, a linq query returns an IQueryable object, which means that the data is not fetched from db until enumerated using foreach, ToArray, ToList or AsEnumerable. When Asp.Net tried to access the IQueryable and fetch the data using foreach, the connection was already closed.

Categories

Resources