LINQ to Entities - Support for Closures (Lambdas)? - c#

I've been working around a problem I have when using LINQ to Entities when using closures.
Apparently, L2E does not support closures. Meaning:
var users = from user in UserRepository.FindAll()
select new UserDTO
{
UserId = user.UserId,
Tickets = from ticket in TicketRepository.FindAll()
where ticket.User == user
select new TicketDTO
{
TicketId = ticket.TicketId
}
};
(NOTE: The "where"-clause is where the problem exists. I am not allowed to compare an entity to another entity because they are not EF primitive types. Only things like Int32, Guid etc. is allowed.)
, is not valid because I cannot compare 'ticket.User' to 'user'
This is simply an example of the problem I have, and I realize that I could compare on the Id, since this a primitive type, as opposed to a closure.
In reality my scenario is alot more complex than this, but this is the scenario I need to solve for now.
A work-around I found online is using a subquery. That DOES work, but for my scenario it's not very effective.
Question:
Do any of you know if:
Entity Framework 4 will support Closures in LINQ to Entities?
There is a better solution to this problem than using sub-queries?
Any additional knowledge you have on this topic will be greatly appreciated!

This is not a problem directly related to closures. The problem is (probably) that you are mixing Entity Framework entities and your data transfer objects. The LINQ provider tries to convert the expression tree of your query into SQL statements and fails because it cannot separate the data transfer objects from the entities and the database, of course, cannot deal with the data transfer objects, too.
I suggest to make the separation much cleaner - at first fetch the data from the database using LINQ to Entity and maybe anonymous types if required, then switch to LINQ to Objects to construct data transfer objects from the retrieved data and all should be fine. Something like the following. (Just to note - I am (safely) assuming the repositories return IQueryable<T>s (else the whole stuff should not work at all).)
var result = UserRepository
.FindAll()
.Select(user => new
{
UserId = user.UserId,
TicketIds = TicketRepository
.FindAll()
.Where(ticket => ticket.User.UserId == user.UserId)
.Select(ticket => ticket.TicketId)
});
Transforming this query result into data transfer objects is now straight forward. Note that the users are compared via the IDs because the Entity Framework does (not yet) support comparisons by reference.

The problem here is that L2E doesn't support reference equality of materialized objects vs. objects in the DB, so you need to compare based on the PK:
var users = from user in UserRepository.FindAll()
select new UserDTO
{
UserId = user.UserId,
Tickets = from ticket in TicketRepository.FindAll()
where ticket.User.UserId == user.UserId
select new TicketDTO
{
TicketId = ticket.TicketId
}
};
(Presuming, here, that the PK of User is called UserId.)

Related

How to Find by object - is there functional similar to Hibernate's .createCriteria() in EF 6.0

I have a lot of objects, each other with a lot of fields.
I used Hibernate createCriteria() functional in Java, that allows to find records in DB by passing initilized object with values in some fields, for example:
Personne personne = new Persone() {field1="f1", field2=123}
List<Personne> listPersonne;
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("testhibernate0");
EntityManager entityManager = entityManagerFactory.createEntityManager();
Session session = entityManager.unwrap(Session.class);
Example personneExample = Example.create(personne);
Criteria criteria = session.createCriteria(Personne.class).add(personneExample);
listPersonne = criteria.list();
entityManager.close();
Hibernate iterates through all fields of passed objects and constructs query based on field values of passed object. So, I don't need to code all fields of object in where() with Hibernate.
The main idea is to find data in DB by fields of object.
Yep, I could code with .where() all fields, but it will be too hard to code all of those fields in .where()
Is there a similar functional in Entity Framework 6.0?
EF has no need for such an API, because LINQ is just much better. You can write a query directly in C# and EF will translate it to SQL and marshal the results into a collection.
Simply:
var q = db.Personne.Where( p => p.field1="f1" && p.field2=123 );
var results = q.ToList();

Is there a way to automatically create CRUD for EF Model (DB First currently)

I am creating a WPF app and I have an existing DB that I would like to use and NOT recreate. I will if I have to, but I would rather not. The DB Is sqlite and when I add it to my data later and create a DataModel based on the DB, I get the model and the DB Context, however there are no methods created for CRUD or for instance .ToList() so I can return all of the items on the table.
Do I need to create all of these manually or is there a way to do it like the way that MVC can scaffold?
I am using VS 2017, WPF, EF6 and Sqlite installed with Nu-Get
To answer the question in the title.
No.
There is no click-a-button method of scaffolding out UI like you get with MVC.
If you just deal with a table at a time then you could build a generic repository that returns a List for a given table. That won't save you much coding, but you could do it.
If you made that return an iQueryable rather than just a List then you could "chain" such a query. Linq queries aren't turned into SQL until you force iteration and you can base one on another adding criteria, what to select etc etc for flexibility.
In the body of your post you ask about methods to read and write data. This seems to be almost totally unrelated from the other question because it's data access rather than UI.
"there are no methods created for CRUD or for instance .ToList() so I can return all of the items on the table."
There are methods available in the form of LINQ extension methods.
ToList() is one of these, except it is usual to use async await and ToListAsync.
Where and Select are other extension methods.
You would be writing any model layer that exposed the results of those though.
I'm not clear whether you are just unaware of linq or what, but here's an example query.
var customers = await (from c in db.Customers
orderby c.CustomerName
select c)
.Include(x => x.Orders) //.Include("Orders") alternate syntax
.ToListAsync();
EF uses "lazy loading" of related entities, that Include makes it read the Orders for each customer.
Entity Framework is an Object Relational Mapper
Which means it will Map your C# objects to Tables.
Whenever you are creating a model from bd it will create a Context Class which will in inherit the DbContext. in this class you will find all the tables in DbSet<Tablename> Tablename{get; set;}. Basically, this list contains will the rows. the operation performed on this list will affect the DB on SaveChange method.
Example for CURD
public DbSet<Student> Students { get; set; }
//Create
using (var context = new YourDataContext()) {
var std = new Student()
{
Name = "Aviansh"
};
context.Students.Add(std);
context.SaveChanges();
}//Basically saving it will add a row in student table with name field as avinash
//Delete
using (var context = new YourDataContext()) {
var CurrentStudent=context.Students.FirstOrDefault(x=>x.Name=="Avinash")
CurrentStudent.context.Students.Remove(CurrentStudent);
context.SaveChanges();
}
Note: on SaveChanges the change will reflect on Db

Passing a GetWhere query (Func<entityDTO,bool>) to a data layer method which needs a (Func<entity,bool>) parameter to work

I have the following method in a data access class which uses entity framework:
public static IEnumerable<entityType> GetWhere(Func<entityType, bool> wherePredicate)
{
using (DataEntities db = new DataEntities())
{
var query = (wherePredicate != null)
? db.Set<entityType>().Where(wherePredicate).ToList()
: db.Set<entityType>().ToList();
return query;
}
}
This works fine when I use the entities across all layers... however I am trying to move to using a DTO class and I would like to do something like the following:
public static IEnumerable<EntityTypeDTO> GetWhere(Func<EntityTypeDTO, bool> wherePredicate)
{
//call a method here which will convert Func<EntityTypeDTO,bool> to
// Func<EntityType,bool>
using (DataEntities db = new DataEntities())
{
var query = new List<EntityType>();
if (wherePredicate == null)
{
query = db.Set<EntityType>().ToList();
}
else
{
query = (wherePredicate != null)
? db.Set<EntityType>().Where(wherePredicate).AsQueryable<EntityType>().ToList()
: db.Set<EntityType>().ToList();
}
List<EntityTypeDTO> result = new List<EntityTypeDTO>();
foreach(EntityType item in query)
{
result.Add(item.ToDTO());
}
return result;
}
}
Essentially I want a method which will convert Func to Func.
I think I have to break down the Func into an expression tree and then rebuild it somehow in the entityType?
I want to do this to allow the Presentation Layer to just pass the Expression queries?
Am I missing something basic or is there an easier design pattern that can pass a query from a DTO to a data access class without knowing the details of the query?
I have tried making the DTO inherit from the entity which doesn't seem to work either?
If there is a better design pattern that I am missing I would love a pointer and I can investigate from there...
Firstly I would suggest that you put a querying layer of your own in front of Entity Framework rather than allowing any arbitrary Func to be passed in because it will be very easy in the future to pass a Func that Entity Framework can not translate into a SQL statement (it can only translate some expressions - the basics are fine but if your expression calls a C# method, for example, then Entity Framework will probably fail).
So your search layer could have classes that you build up as criteria (eg. a "ContainsName" search class or a "ProductHasId" class) that are then translated into expressions in your search layer. This separates your app entirely from the ORM, which means that ORM details (like the entities or like the limitations of what Funcs can and can't be translated) don't leak out. There's lots out there that's been written about this some of arrangement.
One final note, though, if you are working close to the ORM layer, Entity Framework is very clever and you could probably get a long way without trying to translate your Func<dto, bool> to a Func<entity, bool>. For example, in the below code, accessing "context.Products" returns a "DbSet" and calling Select on it returns an IQueryable and calling Where on that also returns an IQueryable. Entity Framework will translate all of that into a single SQL statement so it won't pull all other Products into memory and then filter the ID on that memory set, it will actually perform the filtering in SQL even though the filter is operating on a projected type (which is equivalent to the DTO in your case) and not the Entity Framework entity -
var results = context.Products
.Select(p => new { ID = p.ProductID, Name = p.ProductName })
.Where(p => p.ID < 10)
.ToList();
The SQL executed is:
SELECT
[Extent1].[ProductID] AS [ProductID],
[Extent1].[ProductName] AS [ProductName]
FROM [dbo].[Products] AS [Extent1]
WHERE [Extent1].[ProductID] < 10
So, if you changed your code to get something like..
return context.Products
.Map<Product, ProductDTO()>()
.Where(productDtoWherePredicate)
.ToList();
.. then you might be just fine with the Funcs that you already have. I presume that you already have some sort of mapping functions to get from EF entities to DTOs (but if not then you might want to look into AutoMapper to help you out - which has support for "projections", which are basically IQueryable maps).
I am going to put this up as an answer.Thanks to Dan for the quick answer. Looking at what you are saying I can write a query/filter set of classes. for example, take the following code:
GetProducts().GetProductsInCategory().GetProductsWithinPriceRange(minPrice, maxPrice);
This code would run like so: Get Products would get all products in the table and the remaining functions would filter the results. if all queries run like this it may put a significant load on the Data Access Layer/ DB Server Connections... not sure.
or
An Alternate I will work on also is:
If each function creates a Linq expression, I could combine them like this: How do I combine multiple linq queries into one results set?
this may allow me to do this in a manner where I can return the filtered results set from the database.
Either way I am marking this as answered. I will update when I have more details.

Fluent NHibernate and multiple key columns

I have a User entity that has a IList property. The mapping for
this looks like this:
HasMany(x => x.Forms)
.Cascade.None()
.AsBag().KeyColumn("Supervisor")
.Key(key => key.Not.Update())
.PropertyRef("Email");
Now I have a new feature request in that essentially adds another
KeyColumn that should ALSO populate into this property. Essentially,
each form can have a "Supervisor" and an "Alternate", and I need this
property to populate any Forms where the User.Email is equal to either
one (Forms BELONG to a User IF the User.Email == Form.Supervisor OR User.Email == Form.Alternate).
Is there a way to do this? Simply adding another KeyColumn
specification simply overrides the previous one, and adding keys via
the Keys() method seems to not allow for multiple key columns like I
want... I'm looking for a way to essentially tell it that this
relationship should be found with a WHERE Superviser = Email OR Alternate = Email, but it doesn't seem to support that OR clause...
My other option is essentially duplicate this mapping, but for "Alternate" in another property, and then slam the collections together in my consuming code, but I wanted to see if NHibernate was smart enough for this to be possible...
Any suggestions?
To my knowledge, no - NHibernate does not support this unusual type of join. I would approach this exactly like you said. Use two collections - User.SupervisorForms and User.AlternateForms, then combine them later, perhaps using LINQ's Concat method to do so. You could define a property to do this concatenation for you:
public virtual IEnumerable<Form> Forms
{
get { return SupervisorForms.Concat(AlternateForms); }
}
If you wish to load a User with a completely initialized Forms collection in a single round-trip to the database, then you can use this approach from the Improving Performace - Multi Query section of the NHibernate documentation:
User user = s.CreateMultiQuery()
.Add("select u from User u left join fetch u.SupervisorForms where u.Id = :id")
.Add("select u from User u left join fetch u.AlternateForms where u.Id = :id")
.SetInt32("id", 123)
.UniqueResult<User>();
This code uses CreateMultiQuery() and HQL - but the approach should work just as well with your choice of query batching syntax: CreateMultiQuery(), CreateMultiCriteria(), or Future() / FutureValue().

Why LINQ to Entities won't let me initialize just some properties of an Entity?

So I've started to add Entity Framework 4 into a legacy web application (ASP.NET WebForms).
As a start I have auto-generated some entities from the database. Also I want to apply Repository Pattern.
There is an entity called Visitor and its repository VisitorRepository
In VisitorRepository I have the following method:
public IEnumerable<Visitor> GetActiveVisitors()
{
var visitors =
from v in _context.Visitors
where v.IsActive
select new Visitor
{
VisitorID = v.VisitorID,
EmailAddress = v.EmailAddress,
RegisterDate = v.RegisterDate,
Company = v.Company,
Position = v.Position,
FirstName = v.FirstName,
LastName = v.LastName
};
return visitors.ToList();
}
Please note that Visitor has more properties than those, I just don't want to get everything because there are some heavy TEXT fields.
That List is then bound to a repeater and when trying to do <%# Eval('EmailAddress') #%> it throws the following exception.
The entity or complex type 'Model.Visitor' cannot be constructed in a LINQ to Entities query.
A) Why is this happening? How I can workaround this? Do I need to select an anonymous type and then use that to partially initialize my entities??? I don't want to make a SELECT * because there are some heavy TEXT columns I don't need here
B) Why every example I've seen makes use of 'select new' (anonymous object) instead of initializing a known type? Anonymous types are useless unless you are retrieving the data and showing it in the same layer. As far as I know anonymous types cannot be returned from methods? So what's the real point of them???
Thank you all
a) It's happening because Visitor is an entity. You could say the following with the understanding that you won't be able to update the database via the resulting objects outside the data context in the repository:
var visitors =
from v in _context.Visitors
where v.IsActive
select v;
b) I don't know what example you are looking at but you are right to say that passing a collection of anonymous types from a repository in the data layer to the GUI isn't what you want. You can either use self-tracking entities or data transfer objects (DTOs). This MSDN article explains your options in detail.

Categories

Resources