Prevent fetching reference table values while using entityframework - entity-framework

I am using EntityFramework in my Apllication. If I want to fetch one table value means that will return values with all the referenced table values. It takes time to fetch all the table values. If I need one specified reference table values means
How do I Prevent fetching other reference table values?

If you want to extract single table record without reference tables so you need to define LazyLoadingEnabled false in your DBContext class.
Example your database name is EmpReview
public class UserDataLayerContext : DbContext
{
public UserDataLayerContext()
: base("name=EmpReview")
{
this.Configuration.LazyLoadingEnabled = false;
}
So all the DBSet classes which in UserDataLayerContext filter time only get the single table record without any reference class.
Using this.Configuration.LazyLoadingEnabled = false; none of return reference table calss but in that you need to get single reference table check below example,
Suppose one table class is UserMaster and it is link to GroupMaster master
So
return context.UserMasters.Include("GroupMaster").Where(x => (x.UserID == id) && (x.IsActive ==
true)).ToList();
In that case you get all the usermaster record with group master table.
And
return context.UserMasters.Where(x => (x.UserID == id) && (x.IsActive == true)).ToList();
above case you get all the record of usermaster with out group master table.

Related

EF LINQ Get list of records by values not existing in another list

So, I have junction table called:
AppointmentsActivities
consisting of:
AppointmentID
ActivityID
I need to implement Update operation. Since it's a junction table the update should be able to not only to update existing records, but also to insert new records, or to delete one who no longer need to exists in the table(because i'm passing an entity with an appointmentID and list of ActivityID's).
I'm struggling to delete the records, that no longer should exist in the table.
I have to delete every record which have the same AppointmentId, but his ActivityID should not be present in any of the objects from the new list of Activities.
The query I have written looks like this :
var remove = _context.AppointmentsActivities.
Where(i => i.AppointmentID == entity.ID && entity.Activities.Any(u => u.ActivityID != i.ActivityID)).
ToList();
Where:
i => i.AppointmentID == entity.ID
Checks if the appointmentID of the newly passed entity is the same as the one in the database table.
And:
entity.Activities.Any(u => u.ActivityID != i.ActivityID)
Is supposed to check if any of the activityID's in the list of Activities equals the activityID from the database table.
Obviosly,I'm missing something, because EF cannot resolve this LINQ query. What am I missing? Any help will be appreciated. Thank you.
Try to rewrite your LINQ query to be acceptable by EF. Any with local collections will not work, so replace with Contains:
var activityIds = entity.Activities.Select(a => a.ActivityID).ToList();
var remove = _context.AppointmentsActivities
.Where(i => i.AppointmentID == entity.ID && !activityIds.Contains(i.ActivityID))
.ToList();

Not able to use IN query in LINQ with Entity Framework

I am using EF Framework to retrieve the data from SQL DB.
Sub Request Table looks like below:
In this table "org_assigneddept" is foreign key to another Department Table.
I have list of Departments as Input and I want to retrieve only those rows from DB whose org_assigneddept is matching the list.
Please find my whole code:-
private List<EventRequestDetailsViewModel> GetSummaryAssignedDeptEventRequests(List<EmpRoleDeptViewModel> vmDept)
{
List<EventRequestDetailsViewModel> vmEventRequestDeptSummary = new List<EventRequestDetailsViewModel>();
RequestBLL getRequestBLL = new RequestBLL();
Guid subRequestStatusId = getRequestBLL.GetRequestStatusId("Open");
using (var ctxGetEventRequestSumm = new STREAM_EMPLOYEEDBEntities())
{
vmEventRequestDeptSummary = (from ers in ctxGetEventRequestSumm.SubRequests
where vmDept.Any(dep=>dep.DeptId == ers.org_assigneddept)
select new EventRequestDetailsViewModel
{
SubRequestId = ers.org_subreqid
}).ToList();
}
}
It is giving the following error at the LINQ Query level:-
System.NotSupportedException: 'Unable to create a constant value of
type 'Application.Business.DLL.EmpRoleDeptViewModel'. Only primitive
types or enumeration types are supported in this context.'
Please let me know as how can I achieve the result
You cannot pass the department VMs to SQL, it doesn't know what those are.
// Extract the IDs from the view models.. Now a list of primitive types..
var departmentIds = vmDept.Select(x => x.DeptId).ToList();
then in your select statement...
..
where departmentIds.Contains(id=> id == ers.org_assigneddept)
..

Entity Framework Interceptor to set Id field of patricular entities

In my current project i am working with the database which has very strange table structure (All Id Fields in most tables are marked as not nullable and primary while there is not auto increment increment enabled for them those Id fields need to be unique as well).
unfortunately there is not way i can modify DB so i find another why to handle my problem.
I have no issues while querying for data but during insert What i want to do is,
To get max Id from table where entity is about to be inserted and increment it by one or even better use SSELECT max(id) pattern during insert.
I was hoping to use Interceptor inside EF to achieve this but is looks too difficult for me now and all i managed to do is to identify if this is insert command or not.
Can someone help me through my way on this problem? how can i achieve this and set ID s during insert either by selecting max ID or using SELECT max(id)
public void TreeCreated(DbCommandTreeInterceptionContext context)
{
if (context.OriginalResult.CommandTreeKind != DbCommandTreeKind.Insert && context.OriginalResult.DataSpace != DataSpace.CSSpace) return;
{
var insertCommand = context.Result as DbInsertCommandTree;
var property = insertCommand?.Target.VariableType.EdmType.MetadataProperties.FirstOrDefault(x => x.Name == "TableName");
if (property == null) return;
var tbaleName = property?.Value as ReadOnlyCollection<EdmMember>;
var variableReference = insertCommand.Target.VariableType.Variable(insertCommand.Target.VariableName);
var tenantProperty = variableReference.Property("ID");
var tenantSetClause = DbExpressionBuilder.SetClause(tenantProperty, DbExpression.FromString("(SELECT MAX(ID) FROM SOMEHOWGETTABLENAME)"));
var filteredSetClauses = insertCommand.SetClauses.Cast<DbSetClause>().Where(sc => ((DbPropertyExpression)sc.Property).Property.Name != "ID");
var finalSetClauses = new ReadOnlyCollection<DbModificationClause>(new List<DbModificationClause>(filteredSetClauses) { tenantSetClause });
var newInsertCommand = new DbInsertCommandTree(
insertCommand.MetadataWorkspace,
insertCommand.DataSpace,
insertCommand.Target,
finalSetClauses,
insertCommand.Returning);
context.Result = newInsertCommand;
}
}
Unfortunately that concept of Interceptor is a little bit new for me and i do not understand it completely.
UPDATE
I manage to dynamically build that expression so that ID field is now included in insert statement, but the problem here is that I can not use SQL query inside it. whenever i try to use this it always results in some wrong SQL query so is there anyway i tweak insert statement so that this SELECT MAX(ID) FROM TABLE_NAME is executed during insert?
Get the next id from the context, and then set the parameter of the insert command accordingly.
void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
var context = interceptionContext.DbContexts.First() as WhateverYourEntityContainerNameIs;
// get the next id from the database using the context
var theNextId = (from foo in context...)
// update the parameter on the command
command.Parameters["YourIdField"].Value = theNextId;
}
Just bear in mind this is not terribly thread safe; if two users update the same table at exactly the same time, they could theoretically get the same id. This is going to be a problem no matter what update method you use if you manage keys in the application instead of the database. But it looks like that decision is out of your hands.
If this is going to be a problem, you might have to do something more drastic like alter the command.CommandText to replace the value in the values clause with a subquery, for example change
insert into ... values (#YourIdField, ...)
to
insert into ... values ((select max(id) from...), ...)

Entity Framework SubmitChanges

I have trigger on table A to change the column value on table B during new row insertion on table A.
Due to current design I am getting RowVersion error. So I am thinking to perform current trigger functionality on entity SubmitChanges. I believe that INotifyPropertyChanged fired on property change, in my case will be fired on table A property change, which is I not what I want. I want to perform operation on table A row insertion to update value on table B.
Anyone have idea what is better way to handle it?
You can overwrite SaveChanges, get all entities to be inserted to table A and perform your updates on entities from table B.
public override int SaveChanges(SaveOptions options)
{
foreach(TableA a in ObjectStateManager.GetObjectStateEntries(EntityState.Added)
.Where(e => !e.IsRelationship)
.Select(e => e.Entity)
.OfType<TableA>())
{
// Here you can get your TableB entity and do an update
// If you don't have those entities already loaded you will load
// them one by one so it will probably need some additional
// adjustments for better performance
}
return base.SaveChanges(options);
}

Used 'new' operator in LINQ to SQL query, but same instance is referenced in every result

Can anyone explain the behavior I am seeing in the minimal code example below? It seems that for a given field or property, the same two instances of the Entry class are being reused in each iteration of the LINQ to SQL query, even though I use the new operator. The same problem does not show up for LINQ to objects queries. I created a C# console application project using .NET Framework 4 and connecting to a SQL Server 2005 Enterprise database.
public class Set
{
public Entry Field;
public Entry Property { get; set; }
}
public class Entry
{
public int ID;
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
var dc = new DataClasses1DataContext(); // just create a simple dbml with some table from some database
var resultQuery = (
from x in dc.SomeTable
select new Set()
{
Field = new Entry(),
Property = new Entry()
}
);
var sets = resultQuery.ToArray();
Test(sets);
var source = Enumerable.Range(0, 10);
var sourceQuery = (
from x in source
select new Set()
{
Field = new Entry(),
Property = new Entry()
}
);
var sets2 = sourceQuery.ToArray();
Test(sets2);
}
static void Test(Set[] sets)
{
var f = sets[0].Field;
Console.WriteLine(sets.All(x => object.Equals(x.Field, f)));
var p = sets[0].Property;
Console.WriteLine(sets.All(x => object.Equals(x.Property, p)));
Console.Writeline(sets.Length);
Console.WriteLine(object.Equals(f, p));
Console.WriteLine();
}
}
The output of Test() for the LINQ to SQL query is
True
True
1362
False
which indicates that for all of the Set objects produced, all the Field members point to the same single Entry instance and all the Property members point to the same single Entry instance. I.e., the same instance is reused for a respective member in every iteration of the query.
The output of Test() for the LINQ to objects query is
False
False
10
False
which indicates that a new distinct instance is created in each iteration of the query.
Is the LINQ to SQL behavior expected or a bug? Does anyone know if this happens with the Entity Framework?
I don't know if this is a bug or if and why this is expected in LINQ to SQL. I can only answer your last question if that also happens with Entity Framework.
The answer is: No.
With EF you have to use object initializer syntax though when you instantiate the Entry objects. Using the default constructor leads to an exception:
var resultQuery = (
from x in dc.SomeTable
select new Set
{
Field = new Entry { Name = "X" },
Property = new Entry { Name = "X" }
}
);
It doesn't matter how you initialize. Using the code above (and with 4 rows in a small test table) I get this output with your test program:
False
False
4
False
False
False
10
False
It looks that there is a big difference between LINQ to SQL and Entity Framework regarding object materialization during projections.
(I've tested with EF 4.1/DbContext.)
Edit
If I take the modified query in my code snippet above also for your LINQ to SQL query and watch the generated SQL I get the following:
SELECT NULL AS [EMPTY]
FROM [dbo].[SomeTable] AS [t0]
Whereas the same with LINQ to Entites creates this query:
SELECT
1 AS [C1],
N'X' AS [C2],
N'X' AS [C3]
FROM [dbo].[SomeTable] AS [Extent1]
My interpretation is that LINQ to SQL parses the projection code and queries only columns for property values which depend on the "row variable" x. All other properties are filled on the client when the objects get materialized. If an object does not depend on a column value at all, LINQ to SQL creates a single constant object and reuses it in the whole result collection.
In constrast to this Entity Framework also sends constant values (independent of x) to the database server. The values get send back to the client and EF treats those values as if they were column values and updates the properties of the objects in the projection.
This leads also to the big difference that something like this...
Random random = new Random();
var resultQuery = (
from x in dc.SomeTable
select new Set
{
Field = new Entry { ID = random.Next() },
Property = new Entry { Name = "X" }
}
);
...works in LINQ to SQL because apparently the random function value (which is independent of x) is evaluated on the client and then assigned to the property. But EF wants to translate the right side of the property assignment into SQL and send it as SQL fragment to the database server - which fails and leads to the infamous "...cannot translate into store expression..." exception.
Edit 2
BTW: The last code snippet above still creates only a single Field instance in the whole collection: random.Next() is only evaluated once (and also the constructor of Entry is only called once for the Field object). This now is indeed confusing because writing such code one would expect that you want to have a random value for each row returned from the database. It's not the case.