10

In the below snipped i try to fetch data using Anonymous Projection and i would like do not track the entities that is fetched.

Note : i have already gone through existing stack question,yet unable to find a working solution for me

using (var db = new Entities())
{
     db.Configuration.LazyLoadingEnabled = false;
     db.Configuration.ProxyCreationEnabled = false;

     var myprojection = db.Table1
                        .AsNoTracking()
                        .Include(gh=>gh.Table2) //Update
                        .Include(gh=>gh.Table3) //Update
                        .Select(x => new
                        {
                            table1= x,
                            table2= x.Table2.Where(g => Some Condition),

                            table3= x.Table3.Where(g=>Some Condition)
                        })
                        .ToList();

    var result = myprojection.Select(g =>g.table1).FirstOrDefault();

}

When i useAsNoTracking() data from the inner tables (table2,3) is lost during the conversion at this line var result = myprojection.Select(g =>g.table1).FirstOrDefault();

Edit

If i remove AsNoTracking() everything works fine.

1) How to use projection and AsNoTracking in entity framework correctly ?

2) Any other option to remove tracking of this query?

Is there any possible workarounds?

Eldho
  • 7,795
  • 5
  • 40
  • 77

4 Answers4

1

First of all, it does not make sense to use db.Configuration.ProxyCreationEnabled = false and AsNoTracking() at the same time.

If you use db.Configuration.ProxyCreationEnabled = false change tracking will turn off for all queries.

But your problem with inner tables 2 and 3 is not caused by AsNoTracking().

db.Configuration.LazyLoadingEnabled = false;
db.Configuration.ProxyCreationEnabled = false; 

Turn off lazy loading and i guess it's good for performance reason. If turn it on, you will get expected result, but Entity Framework will make additional SQL query to Data Base for every row in myprojection result. You should better do the following:

using (var db = new Entities())
{
   db.Configuration.LazyLoadingEnabled = false;
   db.Configuration.ProxyCreationEnabled = false;

   var myprojection = db.Table1
                    .Include(x=>x.Table2).Include(x=>x.Table3)
                    .Select(x => new
                    {
                        table1= x,
                        table2= x.Table2.Where(g => Some Condition),
                        table3= x.Table3.Where(g=>Some Condition)
                    })
                    .ToList();

  var result = myprojection.Select(g =>g.table1).FirstOrDefault();

}

Using .Include(x=>x.Table2).Include(x=>x.Table3) in your query will force Entity Framerwork to load related Table2 and Table3 for one query to Data Base.

Eldho
  • 7,795
  • 5
  • 40
  • 77
  • 1
    Include will not work for custom projections. So `Table2/3` Data wont be loaded in `table1` property. But it will be loaded in properties `table2` and `table3` without any `Include`. – tenbits Feb 08 '16 at 15:03
1

Use ToList() for your navigation properties. Note that it will still projekt in the DB. (EF6)

// ..
table2 = x.Table2.Where(g => Some Condition).ToList(),

Update:

With EF4 you probably need to map table2 manually:

 table2 = x.Table2.Where(g => CONDITION).Select(x => new {Foo = x.Bar}),
tenbits
  • 7,568
  • 5
  • 34
  • 53
  • It will throw exception `LINQ to Entities does not recognize the method` – Eldho Feb 08 '16 at 14:53
  • Is your "Some Condition" simple expression? While `ToList` definitely works in EF6. Try to remove condition, will you still get the exception? – tenbits Feb 08 '16 at 15:01
  • Sorry i forget to mention, I'm using EF4, The condition is pretty simple `(SomeVariable == SomeVariable && SomeBoolean)` – Eldho Feb 08 '16 at 15:04
  • Oh, try to make additional select for `Table2`. See my update. – tenbits Feb 08 '16 at 15:05
  • 1
    Additionally, you can see also any time what SQL statement is generated from your query. Without calling the last `ToList()`: `((System.Data.Objects.ObjectQuery)query).ToTraceString()` – tenbits Feb 08 '16 at 15:12
  • 1
    Sorry, then I have no clue for you here, while such thing for sure works with EF6, while I offen do the same things. And, if you say, it works without `AsNoTracking`, then use it without, you can disable `AutoDetectChangesEnabled`, and together with falsy `ProxyCreationEnabled` it would be not needed. – tenbits Feb 08 '16 at 15:44
1

When i useAsNoTracking() data from the inner tables (table2,3) is lost during the conversion at this line var result = myprojection.Select(g =>g.table1).FirstOrDefault();

Your selecting Table1, into an anonymous type you will not have access to table2 or table3 although the navigation properties are they they will not map. Entities loses it relationships when you select into anonymous type you need to select table two and three or don't pull it into an anonymous type.

Just put your wheres directly in the table one where and then make your call

 var myprojection = db.Table1.Join(db.Table2.Where(x => yourcondition), 
                                     t1 => t1.id, t2 => t2.t1id, (t1, t2) => t1 );

then you have to do another join for table3

but your probably better just making the call in two queries

johnny 5
  • 19,893
  • 50
  • 121
  • 195
  • I'm using `ef4` this is not compiling in my scenario. Here `Table1` to Table2 has 1 to many relationship. `Cannot convert IEnumberable to bool exception` – Eldho Feb 08 '16 at 15:10
0

Maybe you can try like this:

using (var db = new Entities())
    {
         db.Configuration.LazyLoadingEnabled = false;
         db.Configuration.ProxyCreationEnabled = false;

         var myprojection = db.Table1 
                            //.AsNoTracking()  //remove.AsNoTracking() from here
                            .Select(x => new
                            {
                                table1= x,
                                table2= x.Table2.Where(g => Some Condition),
                                table3= x.Table3.Where(g=>Some Condition)
                            })
                            .AsNoTracking()//add .AsNoTracking() here
                            .ToList();    

        var result = myprojection.Select(g =>g.table1).FirstOrDefault();    
    }

NOTE: I dont try this. Just an idea, i hope this helps to you

  • I think that it will not work. _AsNoTracking_ will not modify _Table1_ but it will return "a new query where the entities returned will not be cached in the System.Data.Entity.DbContext." – Michał Komorowski Feb 08 '16 at 14:17