EF, get entity tree - c#

I have EF model and I would like to get list of entities names which are somehow related with parent entity.
Lets say thay I have this model.
If I choose entity "Orders" I should get as result Orders, Customers, Order_Details nad CustomerDemographics.
It there a way how to do this?
Thank you.

It is possible to get entity names this way and without reflection:
using (var context = new ModelContainer())
{
var container = context.MetadataWorkspace.GetEntityContainer(context.DefaultContainerName, DataSpace.CSpace);
var entitySet = container.BaseEntitySets[someEntityName];
var navProperties = set.ElementType.Members.Where(member => member.BuiltInTypeKind == BuiltInTypeKind.NavigationProperty).Select(member => member.Name).ToList();
}

Related

How to iterate through models in ModelContext from EntityFramework

I have a ModelContext with hundreds of models generated with EF DB-First (Scaffold-DbContext).
How can I search through the attributes of the models for those who have a property e.g. objid generically. I could hard-code the check for each model, but that is not practical due to the number of tables / models (big enterprise DB).
Say I didn't know of the Students model below. How could I still check for a property?
using (var context = new MyDbContext())
{
var students = context.Students
.Where(s => s.objid == 1234)
.ToList();
}

What is the best way to audit reading of entities with LinQ in EF6?

I have a code-first EF database setup which is accessed with an OData controller from the front end.
I am trying to audit the entities that the user loads.
How can I intercept the materialized entities after LinQ execution?
For example:
var entity = _service.Queryable().FirstOrDefault(x => x.ID == key);
I want to add a custom action after the entity is materialized and have access to it.
I've tried to use the DbContext.Database.Log, but I get only the EF generated queries.
Here is a way to do it with the ObjectMaterialized event
using (var context = new EntityContext())
{
// could be set globally in the constructor
var materialized = new List<object>();
((IObjectContextAdapter) context).ObjectContext.ObjectMaterialized += (sender, args) => materialized.Add(args.Entity);
var list = context.Customers.ToList();
FiddleHelper.WriteTable(materialized);
}
Online Example: https://dotnetfiddle.net/yzmlSO
The solution was actually simple.
Since I only wanted to log user requests from frontend, I extended the OData controller to add audit logs whenever an entity was requested.
This way, no matter what LinQ filtering is done in the backend, I get access to the result of the user request:
var entity = _service.Queryable().Where(x => x.ID == key);
Logger.AddAuditLog(entity);
//... continue execution
Hope this helps someone!

Use table name and column name as dynamic in linq using entity [duplicate]

I want to get list of records from an entity model (I'm using EF version 5) with a particular accountID. I'm being supplied with the tableName string (this has to be dynamic) and the accountID. I'm trying the following 2 methods but none of them is working (giving me errors on the IQueryable object 'table':
PropertyInfo info = _db.GetType().GetProperty(tableName);
IQueryable table = info.GetValue(_db, null) as IQueryable;
var query = table.Where(t => t.AccountID == accID)
.Select(t => t);
List <object> recList = ( from records in table
where records.AccountID == accID
select records).ToList<object>();
The var query = table.Where(....).Select(...) is the correct move as it allows reflection for the query builder at runtime. However, t.AccountID is an error because of the type of t remains unknown.
I've previously used a similar approach in LINQ to SQL, using System.Linq.Expressions.Expression, e.g.:
// NOT TESTED
var table=context.GetTable(dynamicTableName);
var theT=table.Experssion; // actually, I forget. DynamicExpression or MemberBinding? or
var theField=Expression.Field(theT, "AccountID"); // or dynamic name
var query=table.Where(Expression.Equal(theField, accID);
var recList=query.ToList<object>();
If your object has a common interface there is a simpler syntax:
IQueryable<MyInterface> table = context.GetTable("table") as IQueryable<MyInterface>;
var recList=from r in table
where table.AccountID == ac // if your AccountID is on MyInterface
select table;
If you only have a few tables to support, you could do this as well:
IQueryable<MyInterface> table;
if("table1"==tableName)
table=_db.table1
elseif("table2"==tableName)
table=_db.table2
elseif("table3"==tableName)
table=_db.table3
else
throw exception
I built a DynamicRepository for a project I am working on. It uses generic methods exposed through EF along with dynamic linq. It might be helpful to look at that source code here:
https://dynamicmvc.codeplex.com/SourceControl/latest#DynamicMVC/DynamicMVC/Data/DynamicRepository.cs
You can query the entity framework metadata workspace to get the type for a given table name. This link might help:
Get Tables and Relationships

EF: Clear Collection Property without First Getting Data

I have a class called Facility. Facility has a collection property on it called Employees. I'm using the disconnected layer of EF. I want to clear the Employees collection from a specific facility, but I don't want to make two trips to the DB: (1) getting all the employees, and then (2) clearing the. How can I do this?
Here's what I've tried...
Facility f = new Facility()
{
Id = 4,
Employees = new List<Employee>()
};
context.Facilities.Attach(f);
context.Entry<Facility>(f).Collection(fac => fac.Employees).IsLoaded = true;
context.SaveChanges();
I think I'm close, but it doesn't work. Thanks for the advice.
If you want to use EF only, you're always going to need some roundtrip. In the end, EF needs to generate DELETE ... WHERE Id = x statements. How would it know the values for x without first grabbing them from the database?
But of course you can do this in a more efficient way than fetching the complete Employee objects. It's enough to get the Id values. Then you can use these Ids to create stub entities that you mark as Deleted:
var ids = context.Empoyees.Where(e => e.FacilityId == 4)
.Select(e => e.Id).ToArray();
foreach(int id in ids)
{
var emp = new Empoyee { Id = id }; // Stub entity
context.Entry(emp).State = System.Data.Entity.EntityState.Deleted;
}
context.SaveChanges();
This is pure EF. But you can also use EntityFramework.Extended. This allows you to execute a statement like
context.Empoyees.Where(e => e.FacilityId == 4)
.Delete();

With entity framework's self tracking entities, can I perform an explicit load?

I wish to return a graph for a "Business" entity. The Buiness entity has a collection of "Contacts".
So I basically want this:
ctx.Business.Include("Contacts").Where(b => b.BusinessID == id).Single();
The problem is I don't want ALL the contacts for the business. Just those that have a ContactTypeID = x. How can I accomplish this? I figured I may need to break the query into 2 steps. 1 to get the business and a 2nd to grab the contacts and then attach them to the business somehow.
But I'm using using the STE t4 template and I can't figure out how to do it using that.
I'd greatly appreciate any help.
One way for doing so is:
var biz = from b in ctx.Business where b.BusinessID == id
select new
{
Business = b,
Contacts = b.Contacts.Where(c => c.ContactTypeID == x)
}.ToList();
I think I found how to do it:
var biz = ctx.Business.Where(b => b.BusinessID == id).Single();
var contacts = ctx.Contacts.Where(c => c.BusinessID==id && c.ContactTypeID==6);
foreach (var contact in contacts)
{
biz.Contacts.Add(contact);
}
I was worried by adding the contacts this way they would be treated as "new" items but change tracking is off so they are treated as unchanged. I think change tracking only turns on once they are deserialized.

Categories