Whats wrong with LINQ to EF? - asp.net-mvc

I am using EF. This is my LINQ query
public List<Tuple<int, string>> GetList()
{
return (from c in DALContext.MST
select new Tuple<int, string>(c.CD, c.NAME)).ToList();
}
When i call GetList() it throws an exception : Only parameterless constructors and initializers are supported in LINQ to Entities
Instead when i rewrite this query:
List<Tuple<int, string>> lst = new List<Tuple<int, string>>();
var query= (from c in DALContext.MST
select new{c.CD, c.NAME});
foreach (var item in query)
{
lst.Add(new Tuple<int,string>(item.CD,item.NAME));
}
return lst;
It just works fine. Whats wrong with my first query???

The other answers are correct about what's going on, but I didn't see anyone mention the best way to make your code work: AsEnumerable()
public List<Tuple<int, string>> GetList()
{
return (from c in DALContext.MST.AsEnumerable()
select Tuple.Create(c.CD, c.NAME)).ToList();
}
The AsEnumerable method acts as a boundary between the code that should be translated into SQL and executed in the database server, and the code that should be executed in memory after we've gotten a response from the database. Putting it right after the table name tells EF to get all the records from the MST table, and then run the following code that creates tuples from the values that are returned.
I changed your new Tuple<int, string> into Tuple.Create mostly because I don't like typing generic type parameters any more than I have to.

LINQ to EF deals with queries a bit differently than LINQ to SQL. In LINQ to EF, you can not put a constructor with parameters in a LINQ expression, like you did here in the first bit of code:
from c in DALContext.MST
select new Tuple<int, string>(c.CD, c.NAME)
The constructor of Tuple is taking two parameters, and that is not allowed in LINQ to EF.
The reason is explained here:
In part this is a matter of wanting
LINQ to Entities to be more explicit
about the boundary between what parts
of your query execute on the server
and what part execute on the client.
With LINQ to SQL, for instance, it is
possible to write a LINQ query which
not only involves data from the server
and functions on the server but also
functions that can only be executed on
the client and to mix them in
together. The LINQ to SQL provider
will then do its best to untangle
things and execute the parts that it
can on the server and other parts on
the client. This is nice because it
is easy to just write whatever query
you want and if at all possible it
will work. On the other hand, it's
not so nice if you accidentally write
a query where the only part which can
execute on the server is the most
basic thing that returns all the data
in one or more tables and then have
all the filtering happen on the client
(with very nasty perf consequences).
With LINQ to Entities, the boundaries
are more explicit. When you write a
LINQ query against a LINQ to Entities
IQueryable implementation, the entire
query executes on the server, and if
some part of the query cannot be
executed on the server, then an
explicit boundary must be created with
something like ToQueryable() or
ToList(). Once that query is executed
and the data retrieved, then you can
use LINQ to Objects to further refine
the query if you so choose. This way
you explicitly know where your
boundaries are, and it's easier to
track down performance issues and the
like. One of the related limitations
is that the select statement in LINQ
to Entities can create anonymous types
or other types as long as they have a
default constructor and settable
parameters. This minimizes the chance
that the select statement has major
side effects.

Or you could just write
var query= (from c in DALContext.MST
select new{c.CD, c.NAME}).ToList().Select(x=>new Tuple(x.CD, x.NAME));
This has the advantage it only brings from the DB the two columns you need.

Your class needs to have a parameterless constructor for Linq to EF and you have to instantiate it like this:
public List<Tuple<int, string>> GetList()
{
return (from c in DALContext.MST
select new Tuple<int, string>(){CD = c.CD, Name = c.NAME}).ToList();
}
EDIT:
If you are not in the position to add a parameterless constructor to TUPLE (which is the case here as Tuple is not an class per se) then you have no choice with Linq to EF but to do this as a two step process:
public List<Tuple<int, string>> GetList()
{
List<MST> mstList = (from c in DALContext.MST
select c).ToList();
List<Tuple<int, string>> tupleList = new List<Tuple<int, string>>();
mstList.foreach(c => tupleList.add(new Tuple(c.CD, c.Name)));
return tupleList;
}

Related

About AsEnumerable() behavior

I have an ASP.NET MVC application. Let's suppose that I have this view:
#model IEnumerable<MyClass>
.....
On the server side, I have a linq query, to my database, using EF:
public ActionResult Index()
{
var query = from t in context.MyClass
select t;
//now comes the question
return View(query);
return View(query.AsEnumerable()); //is there any difference?
}
I think that the AsEnumerable() is not necessary because the query will automatically cast to it, so, can someone explain me when the AsEnumerable() is useful?
Thank you!
It is not necessary. The query you have declared results in a sequence, which implements the IEnumerable interface.
As you will see here, the Select extension method of types that implement the IEnumerable, returns a IEnumerable.
public static IEnumerable<TResult> Select<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, TResult> selector)
Your query
var query = from t in context.MyClass
select t;
will be compiled to
var query = context.MyClass.Select(x=>x);
hence I am refering to the Select extension method.
Regarding now the use of AsEnumerable()
The AsEnumerable(IEnumerable) method has no effect other than to change the compile-time type of source from a type that implements IEnumerable to IEnumerable itself.
Also
AsEnumerable(IEnumerable) can be used to choose between query implementations when a sequence implements IEnumerable but also has a different set of public query methods available. For example, given a generic class Table that implements IEnumerable and has its own methods such as Where, Select, and SelectMany, a call to Where would invoke the public Where method of Table. A Table type that represents a database table could have a Where method that takes the predicate argument as an expression tree and converts the tree to SQL for remote execution. If remote execution is not desired, for example because the predicate invokes a local method, the AsEnumerable method can be used to hide the custom methods and instead make the standard query operators available.
For further documentation, please have a look here.

Error in breeze using EF 5 and calling stored procedure

Getting an error client side with breeze: "Cannot call method 'map' of undefined" when trying to pull over some data. The difference between this action and one that works is that this action is calling a stored procedure and returning ObjectResult<T> instead of DbSet<T>.
Might this be why I get an error? Using Chrome Developer tools, I do see that the breeze controller is returning json data.
I have created a complex model type in the edmx for mapping the rows returned from the stored procedure.
The action in the breeze controller has a return type of IEnumerable<T>.
I experienced the same error when using an EF complex type. A workaround was to create a view in my database instead of using a complex type, set the stored procedure to return a type of the new view which had a primary key and then it worked. It would seem that breeze requires entities to have a primary key defined.
Hm... not quite sure what is happening, so just guessing here, but try adding an AsQueryable() to the result returned, and changing the result type to a IQueryable.
We don't have any stored proc tests for breeze yet, but this is impetus for me to add some :)
I had the very same issue, but thank God I figured out a solution. Instead of using a stored procedure, you should use a view, as Breeze recognizes views as DbSet<T>, just like tables. Say you have a SQL server table that contains two tables Customers and Orders.
Customers (**CustomerId**, FirstName, LastName)
Orders (OrderId, #CustomerId, OrderDate, OrderTotal)
Now, say you want a query that returns orders by CustomerId. Usually, you would do that in a stored procedure, but as I said, you need to use a view instead. So the query will look like this in the view.
Select o.OrderId, c.CustomerId, o.OrderDate, o.OrderTotal
from dbo.Orders o inner join dbo.Customers c on c.CustomerId = o.CustomerId
Notice there is no filtering (where ...). So:
i. Create a [general] view that includes the filtering key(s) and name it, say, OrdersByCustomers
ii. Add the OrdersByCustomers view to the entity model in your VS project
iii. Add the entity to the Breeze controller, as such:
public IQueryable<OrdersByCustomers> OrdersByCustomerId(int id)
{
return _contextProvider.Context.OrdersByCustomers
.Where(r => r.CustomerId == id);
}
Notice the .Where(r => r.CustomerId == id) filter. We could do it in the data service file, but because we want the user to see only his personal data, we need to filter from the server so it only returns his data.
iv. Now, that the entity is set in the controller, you may invoke it in the data service file, as such:
var getOrdersByCustomerId = function(orderObservable, id)
{
var query = breeze.EntityQuery.from('OrdersByCustomerId')
.WithParameters({ CustomerId: id });
return manager.executeQuery(query)
.then(function(data) {
if (orderObservable) orderObservable(data.results);
}
.fail(function(e) {
logError('Retrieve Data Failed');
}
}
v. You probably know what to do next from here.
Hope it helps.

MVC and Entity Framework Key

I am new to MVC and EF and am having a heck of a time getting an EF query to work, specifically with the EF key="". After adding some test code, the error being returned here is 'The name idAddress does not exist in the current context'. There is a primary key on the Address table named idAddress - identty int
I have read through many suggestions on the site and can't get past this.
private motion_care_360Entities db = new motion_care_360Entities();
public ActionResult GetItems(GridParams g)
{
var list = db.Addresses.Include("AddressCountry").Include("AddressState").Include("AddressType").AsQueryable();
var list1 = list.OrderBy(o => idAddress).ToList();
var l1 = list1[0].AddressState.State;
return Json(new GridModelBuilder<Address>(list, g)
{
Key = "idAddress", // needed when using Entity Framework, usually it's Id
// If you're using EF, it's needed so that the data will be ordered by it before paging it
Map = o => new
{
AddressTypeType = o.AddressType.Type,
AddressStateState = o.AddressState.State,
AddressCountryCountry = o.AddressCountry.Country,
o.City,
}
}.Build());
}
}
That would need to be list.OrderBy(o => o.idAddress).ToList();
You need to specify that it's by the idAddress of the object (i.e. o from your lambda expression) itself.
You're actually confused about a lot of things. First, the issue you claim you have has nothing to do with either MVC or EF. It has to do with whatever GridModelBuilder is, and since that's not a part of MVC, you must be using some third party control for that.
Second, I'm guessing (since I don't know what third party control you're using) that Key is used when using GroupBy, not when using OrderBy. OrderBy does not have a key, but GroupBy does. But it's hard to know, since you seem to think that third party tools are part of the framework.
Third, your OrderBy is assigned to list1, which you never use. You use list, which is unordered.
Fourth, you don't need AsQueryable as it's already a Queryable.

paginatedlist throwing an error "Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator."

I have looked here :
LINQ To SQL exception: Local sequence cannot be used in LINQ to SQL implementation of query operators except the Contains operator
and here :
LINQ to Populate a range
but I can't figure this one out. I have based my Task Manager on the NerdDinner project. Instead of FindUpcommingDinners I have a method below :
Public Function FindAllTeamTasks(ByVal TeamRole As String) As IQueryable(Of Task) Implements ITaskRepository.FindAllTeamTasks
Return From task In db.Tasks
Join usrs In System.Web.Security.Roles.GetUsersInRole(TeamRole)
On task.TaskAssignedToID Equals usrs
Order By task.InsertDateTime _
Select task
End Function
When the result is passed into the Paginatedlist as source it errors with the "Local sequence cannot ..." error. The answer might be here as well but I can't figure it out. Please help.
ASP.NET MVC2 LINQ - Repository pattern, where should the pagination code go?
You can't use the result of GetUsersInRole() in a join to a database table via LINQ to SQL. You can try this instead:
Dim usrs = System.Web.Security.Roles.GetUsersInRole(TeamRole)
Return From task In db.Tasks _
Where usrs.Contains(task.TaskAssignedToID) _
Order By task.InsertDateTime _
Select task
Whenever your are using Linq to SQL, your query has to be able to be translated into SQL to be run against your database. The Linq provider for Linq to SQL only knows how to do this for very certain operations that would occur outside the database. So, for instance, Linq to SQL has no idea what to do with
Join usrs In System.Web.Security.Roles.GetUsersInRole(TeamRole)
because GetUsersInRole is not (as far as Linq is concerned) a table in the database, but rather a collection in your application.
As the error message mentions, there is an "exception" in that, in some cases, Linq to SQL does know what to do with Contains (by turning it into IN in SQL, if I recall) for a collection that does not reside in the database. With that in mind, you might turn your query into something like (sorry it's in C#, but I hope you can translate):
string[] users = System.Web.Security.Roles.GetUsersInRole(TeamRole);
return db.Tasks
.Where<Task>(t => users.Contains<string>(t.TaskAssignedToID))
.OrderBy<Task, DateTime>(t => t.InsertDateTime)
.AsQueryable<Task>();
Now, if your join was there because TaskAssignedToID was a collection and not merely a string (I'm not familiar with the model you're using, sorry), you might instead need to do something like
string[] users = System.Web.Security.Roles.GetUsersInRole(TeamRole);
return db.Tasks
.Where<Task>(t => t.TasksAssignedToID.Any<string>(i => users.Contains<string>(i)))
.OrderBy<Task, DateTime>(t => t.InsertDateTime)
.AsQueryable<Task>();
I'm not 100% sure that Linq to SQL is fine with Any -- I work mostly with Linq to Entities -- but I hope this makes some sense.

Using ASP.NET MVC without an ORM

In my ASP MVC application I'm using standard SQL (rather that Linq to SQL or other ORM) to query my database.
I would like to pass the database results to my view and iterate over the results in my view. But I'm not sure how to do this. Every example I've seen passes some string or uses L2S. I would like to pass something like nested Hashtables, but the only thing I can think of is to pass an SqlDataReader object to the view, but this sounds like a really bad idea.
How would I go about displaying my database results from a standard SQL query to my view? I would really like use Linq or other ORM, but requirements dictate we don't (don't ask me why, I don't understand). I'm doing this in VB. I'll try by best to convert any C# examples provided.
You could create simple classes for the data you want to transfer and then populate a List of objects in your controller from a data reader manually, and then pass this to your View - e.g. (C# but this should be easy to convert)
// open your connection / datareader etc.
List<Customer> customers = new List<Customer>();
while(dataReader.Read())
{
Customer c = new Customer();
c.Id = dataReader.GetInt32(0);
c.Name = dataReader.GetString(1);
// etc (you might want to use string indexers instead of ints for the get methods)
customers.Add(c);
}
// close and dispose your datareader / connection etc as usual
return View("List", customers);
MVC is about separation of concerns. Passing SqlDataReaders, DataTables, or whatever class that resides in the System.Data namespace to a view is not a good idea. You need to define a model which might talk to the database, and a controller which will pass this model to the view. If your company policy says don't use an ORM then maybe classic WebForms are better suited to your scenario than the MVC pattern.
I agree with Rashack. This article explains it in some detail.link text
In a nutshell, here's how to do it using DataTable and DataReader:
private DataTable GetData()
{
DataTable dt = new DataTable();
using (SqlConnection connection
= new SqlConnection("ConnectionString"))
using (SqlCommand command = new SqlCommand())
{
command.Connection = connection;
command.CommandText = "SELECT * FROM Customers";
connection.Open();
using (SqlDataReader reader =
command.ExecuteReader
(CommandBehavior.CloseConnection))
{
dt.Load(reader);
}
}
return dt;
}
Then, you can read that DataTable into an entity object that you pass around.
I think you'll find this can yield much better performance than using Linq or an ORM.
Try using DataTables - DataTable can load data from IDataReader... (I think the method's called Load)
You could create your own Data Transfer Object classes and populate instances of them using ADO.Net code. These DTO classes would be simple POCO-style classes that just contained property get/set accessors, no methods. Using POCO objects is arguably preferable to DataSets/DataTables as they are lightweight (no superfluous state) and are more intuitive to work with from an object-oriented perspective.

Resources