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.
Related
I am new to entity framework and I am trying to get my head around it. I am used to writing stored procedures which have all the data I need on a example by example basis.
I am under the impression that I can get all values from a particular table including the foreign key values direct using entity framework without having to write a select query which joins the data.
I have the following in my controller
public ActionResult Patient()
{
using (var context = new WaysToWellnessDB())
{
var patients = context.Patients.ToList();
return View(patients);
}
}
In my view I have the following
#foreach (var item in Model)
{
<p>
#item.FirstName #item.Surname #item.Gender.GenderDesc
</p>
}
I have two tables, Patient and Gender, GenderId is a foreign key which I am trying to get the GenderDesc from that table.
I am getting the following message
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
Can someone explain why I cannot access GenderDesc. It does work if I remove the using() around my context, but I don't really want to leave that open, is there a way to get this to work still having the using around?
Thanks in advance.
Correct, you have disposed of the context as it is within a using statement, so anything you try to access from then on will not be able to be lazy loaded. The disadvantage with lazy loading is that it will perform a query for the gender for every patient you are iterating over, which is handy, but bad! I would load the related table at query time using Include.
You'll need a new import:
using System.Data.Entity;
And then include the related table:
var patients = context.Patients.Include(p => p.Gender).ToList();
That will result in a query which will join to your "Gender" table and you should be able to output item.Gender.GenderDesc in your view.
I am working on an ASP.NET MVC 4 web application. I am using Entity Framework as the data access layer, using database first approach (.edmx file).
Currently I have a problem in join tables that are defined inside two different databases (i.e. I have two .edmx files).
For example if I want to join tables I am performing the following query:-
public ActionResult AutoComplete(string term)
{
var tech = repository.AllFindTechnolog(term).Take(100);//Call to the first database
var resources = repository.GetResources(tech.Select(a => a.IT360ID.Value).ToArray(), false);//call to the second database
var query = from techItems in tech
join resourcesItems in resources
on techItems.IT360ID.Value equals resourcesItems.RESOURCEID // join based on db2ID
orderby techItems.PartialTag
select new //code goes here
return Json(query, JsonRequestBehavior.AllowGet);
}
I will have two separate calls to the database, and a join inside the application server, which is not the best performance-oriented solution. Ideally the joins will happen completely inside the database engine.
I know that a stored procedure will allow me to join tables from different databases purely on the server, but I do not want to use SP because it will make my code less maintainable and less testable.
So I am searching for a solution where I can do the join using entity framework and to result in a single database join?
If you want to do it with a single database call you will have to create a View in the database that joins the 2 tables from separate db's. Once the view is created you can add it to EF as a single object, which you can manipulate further and Query off of. The view will basically be a table and it will be easily maintable and easy to bind to a strongly typed model
Another way ,similiar like you have posted, you can query separate .edmx files and then join them.
Yes, there is 2 calls to the database but it shouldn't be that expensive and probably won't notice a difference.
using(var db = new MyEntities())
using (var db2 = new MyEntities2())
{
var one = db.Table1.AsEnumerable();
var two = db2.Table2.AsEnumerable();
var result = from o in one
join t in two on o.Id equals t.Id
// blah blah
}
#CSharper's answer is close. As #Oliver mentioned in the comments, IEnumerable loads the table into application memory, leading to crashes if you have a large database.
The solution is to use IQueryable, which can be called with LINQ - this produces SQL which is much faster.
// This is a generic method, modify to your needs
public ActionResult Details(int? id)
var one = db.Table1.AsQueryable();
var two = db2.Table2.AsQueryable();
// since you're using MVC EF, I assume you want to put this in a viewmodel
// (in this case ObjectCombined)
// assume "id" is passed as parameter
Object1 result1 = (from o in one where one.id == id select o).Single();
Object2 result2 = (from t in two where t.id == o.id select t).Single();
ObjectCombined result = new ObjectCombined(result1, result2);
return View(result);
}
Might I suggest that you look into using a synonym in your database. For instance, you can create a synonym to the resources table in the database that your tech table is located. This will ensure that you will not need to maintain 2 EDMX files. Instead you can have a single EDMX file and you can simply join your tech table to the synonym of the resource table and voila - you are on your way.
UPDATE: Please note that if you are using synonyms there is an extra bit of work you will need to do to the EDMX file to get it working in Entity Framework. Here is a blog post that was put out by a programmer who got it to work. Here is the original stackoverflow question she asked.
HAPPY CODING!!! :)
you can create a view or a stored procedure, your sql statement can then make cross db query just make sure your credentials can DML or DDL on both db. otherwise try the nested using entities that will make sure you will not get the linq bug when you dont declare the db entity inside a using statement.
New to Entity Framework .Using EF4. I have found articles and managed to use stored procedures to return a list of entities.
But cannot see/work out how you return a single entity.
Given that I have a stored procedure "GetCustomerById" that return a single customer How do I map it?
Using the Model Browser I right click on "Function Import" and I have added my StoredProcedure
however whatever I select does not seem to return a "Single Entity"
Am I missing the obvious?
thanks a lot for any link or suggestions
When you do Function Import you need to select the entity your SP returns from the drop down (i.e. Customer). The catch is EF does NOT directly returns Customer object as per your selection but System.Data.Objects.ObjectResult which implements IEnumerable.
To be more specific, here is the generated code for your function:
public ObjectResult<Customer> GetCustomerById(Nullable<global::System.Int32> Id)
That's because EF has no idea if your SP returns a single record or a list of them so it wraps the result inside ObjectResult. You can enumerate through this to get your Customer entity like any other IEnumerable object. For example:
Customer myCustomer = context.GetCustomerById(1).First();
I have a Linq to Sql Entity which has an EntitySet. In my View I display the Entity with it's properties plus an editable list for the child entites. The user can dynamically add and delete those child entities. The DefaultModelBinder works fine so far, it correctly binds the child entites.
Now my problem is that I just can't get Linq To Sql to delete the deleted child entities, it will happily add new ones but not delete the deleted ones. I have enabled cascade deleting in the foreign key relationship, and the Linq To Sql designer added the "DeleteOnNull=true" attribute to the foreign key relationships. If I manually delete a child entity like this:
myObject.Childs.Remove(child);
context.SubmitChanges();
This will delete the child record from the DB.
But I can't get it to work for a model binded object. I tried the following:
// this does nothing
public ActionResult Update(int id, MyObject obj) // obj now has 4 child entities
{
var obj2 = _repository.GetObj(id); // obj2 has 6 child entities
if(TryUpdateModel(obj2)) //it sucessfully updates obj2 and its childs
{
_repository.SubmitChanges(); // nothing happens, records stay in DB
}
else
.....
return RedirectToAction("List");
}
and this throws an InvalidOperationException, I have a german OS so I'm not exactly sure what the error message is in english, but it says something along the lines of that the entity needs a Version (Timestamp row?) or no update check policies. I have set UpdateCheck="Never" to every column except the primary key column.
public ActionResult Update(MyObject obj)
{
_repository.MyObjectTable.Attach(obj, true);
_repository.SubmitChanges(); // never gets here, exception at attach
}
I've read alot about similar "problems" with Linq To Sql, but it seems most of those "problems" are actually by design. So am I right in my assumption that this doesn't work like I expect it to work? Do I really have to manually iterate through the child entities and delete, update and insert them manually? For such a simple object this may work, but I plan to create more complex objects with nested EntitySets and so on. This is just a test to see what works and what not. So far I'm disappointed with Linq To Sql (maybe I just don't get it). Would be the Entity Framework or NHibernate a better choice for this scenario? Or would I run into the same problem?
It will definately work in Entity Framework that comes with .NET 4 (I'm doing similar things in the RC version)
This does not explain the exception but:
You should dispose the ObjectContext that's (most likely) wrapped in your repository. The context caches items, and should only be used for a single unit-of-work.
Try to use a pattern like:
public ActionResult Update(int id, MyObject obj) // obj now has 4 child entities
{
using(var repository = CreateRepository())
{
var obj2 = _repository.GetObj(id);
if(TryUpdateModel(obj2))
{
repository.SubmitChanges();
}
else
.....
}
return RedirectToAction("List");
}
When fetching items, create a new repository as well. They are cheap to create and dispose, and should be disposed as quickly as possible.
Ok, so let me explain a little of what I am trying to do.
I have a table called WebsitePage that contains all of the pages on my site with some information about them. Then, I have a Customer table for all of my customers. Then I have another table called CustomerWebsitePage that stores customer values for some of the columns in the WebsitePage table.
So, using the entity framework, I imported these three tables. What I want to be able to do is return a strongly typed WebsitePage list that has any values from CustomerWebsitePage if there are any values for it. So, for example, say one of my customers added a CustomerWebsitePageName for one of my website pages. I want to return a list of WebsitePages that contains the CustomerWebsitePageName instead of the WebsitePage Name in that case. But the original WebsitePage Name for everything else since it wasn't overridden.
The kicker here is that my WebsitePage table has a foreign key to itself for a Parent/Child relationship. So, I also want to return the child WebsitePages at the same time. I tried using a function import to get what I wanted, but then of course I lost the ChildPages.
I have tried just about everything to get what I want using the Entity framework and LINQ. But so far almost everything I try ends up with an exception being thrown. Here are a few:
The EntityCollection has already been initialized
The entity or complex type 'MyEntityModel.WebsitePage' cannot be constructed in a LINQ to Entities query.
I have one idea of how I can get around all this, and that would be to duplicate the ParentPageID into my WebsitePage table, but this really seems to violate a lot of principles and I really just don't want to add the maintenance headache related to this.
Anyone have any ideas how to accomplish this type of thing?
A simple DB diagram. http://images.tehone.com/screenshots/2009-08-17_013009.png
The object that you need to return is a CustomerWebsitePage and not a WebsitePage. The reason is that whatever object you return must know about the customer since the property will need it to determine which field (CustomerPage or WebsitePage) to use.
Considering that, you can have a function CustomerWebsitePage.GetAllPagesForCustomer(Customer c) that would return an enumeration of pages. However, to achieve the functionality you are looking for, you must implement some read-through properties in the CustomerWebsitePage. Let's take the example of Name. Here would be how to implement it in CustomerWebsitePage:
public string Name
{
get{ if( String.IsNullOrEmpty(CustomerWebsitePageName) )
return WebsitePage.Name;
return CustomerWebsitePageName; }
}
For the Children pages, you could have a property:
public IEnumerable<CustomerWebPage> Children
{
get
{
return WebsitePage.Children.Select( it => it.Customer.CustomerID == this.CustomerID ); }
}
Note that with this setup you couldn't run EF Linq queries on these new fields (because they exist only in the objects themselves, not in the database mapping). You can pepper the code with Load() if you want to seamlessly load all the children, but it will cost you in performance. To ensure that all the children are loaded, try the following loading function:
IEnumerable<CusomterWebPage> GetAllPagesForCustomer(Customer c)
{
return Context.CustomerWebPageSet.Include("WebsitePage").Where( it => it.Customer.CustomerID == c.CustomerID );
}