We need to store a list of data we pull from another table that relates to one of our models. (We are too deep into build to add this relationship to our DB where it should be.) When we attempt to load this list in a property of the model that needs it.
We load this list into a dropdown in a view. The error occurs trying to load this list into the model in the controller. The true caveat is that we have a unique dropdown list for each record in our table in the view.
Our Class:
Public class OurModel
public property ID As Integer
Public property First As Integer
Public property Last As Integer
Public property myList As List(Of SelectListItem)//This is our problem member
End class
Controller:
//This ViewModel is what we pass around from page to page to populate the various elements we need that is not tied to a specific model
Public Function LoadList(myViewModel As ViewModel) As Action Result
Using db //our database resource
For i As Integer = 0 to myViewModel.OurModel
//Assume table select statement previously declared and initialized into dbGet
**NOTE: dbGet is retieving data from a different table that is tied to this Model**
dbGet = dbGet.Where(Function(x) x.ID = myViewModel.OurModel.ID)
myViewModel.OurModel.myList = dbGet.ToList().[Select](Function(x) New SelectListItem() With {.Value = x.number, .Text = x.number})//ERROR IS HERE
Next
End Using
End Function
Error:
LINQ to Entities does not recognize the method 'DB.ModelTable get_Item(Int32)' method, and this method cannot be translated into a store expression.
UPDATE: The issue appears to be that LINQ is trying to do something with a the DBContext of a query I do previously in this controller. The error is referencing DB.Employee not DB.Position which is what I am querying.
I have done almost nothing in VB.Net, but it sounds like get_Item(Int32) may be the same as an indexer in C#.
There's a well-known shortcoming that Entity Framework does not support classes that contain an indexer (even if you decorate that property with NotMapped).
I was faced with a similar issue, which was to implement a lockable ObservableCollection. I found that I could not implement IList<T> due to the indexer issue in EF, but that I could implement ICollection<T>.
Lock / Unlock ObservableCollection<T>
If you can replace the semantics of a list with those of a collection, that should solve this problem.
I ended up having to write new classes that connected to the database outside of Entity Framework. If you want to use Entity Framework, make sure you database design is PERFECT before you begin building your application and good luck.
Related
I have tried this using a List and it retains the value fine, but when i change it to a stack the value is lost. I have been stepping through but I can't understand why its gone.
public ActionResult AddToOrder()
{
//Get logged in student from db
var student = _db.Students.Find(User.Identity.GetUserId());
//Create a new Order
var order = new Order();
//add all elements from Student collection to Order collection
foreach (var app in student.Applications)
{
order.Applications.Add(app);
}
//assign order FK
order.StudentId = User.Identity.GetUserId();
//Push the order to the students Stack collection
student.Orders.Push(order); //(When the Student implements a List collection the value
//passes to the Stripe controller with no problems)
//add order to db & save changes
_db.Orders.Add(order);
_db.SaveChanges();
//redirect to stripe controller
return RedirectToAction("Create", "Stripe");
}
//STRIPE CONTROLLER
public ActionResult Create(string stripeToken)
{
var student = _db.Students.Find(User.Identity.GetUserId());
student.Orders.Count // = 0 with Stack
// = 1 with List
}
The only thing I change is Stack to List in the Student entity and push to add. Anybody any ideas whats going on?
I guess I could achieve what I want (LIFO) by using a list in this way. I would still like to know what's going on with my stack though.
myList.Insert(0, order) - - - my List.First()
Student is an Entity Framework entity - an object representation of a database table. Its Orders property represents a relationship to another table. When you add order objects to a Student's Orders property, Entity Framework does a ton of stuff under the hood to make sure that all of the object data is correctly written to the database as table data, with all of the proper foreign keys and such, when you call SaveChanges. Same thing when you call Students.Find: There's a lot of stuff going on to translate your code to a SQL query, run it, then turn the resulting SQL table data into a convenient Student object.
Entity Framework does all of that automatically, but in order for it to work, entity classes like Student need to be defined in a particular way such that EF knows how to handle them. To put it succinctly: properties like Orders that represent relationships to another table need to be Lists. When you redefine Student.Orders to be a Stack, the Entity Framework machinery breaks, and EF can no longer use Orders to work with that portion of the database.
When your app redirects from one controller to another, the orders data is not retained in memory in the app, only in the database. When the target controller loads, your code is trying to load the data from the database that the previous controller was supposed to have saved there. One of two things is happening:
Your change to use Stack broke the Students entity such that the data doesn't get saved to the database at all, OR
Entity Framework can manage to handle Stack well enough to save the data, but not load it.
I'm not sure which is happening with this particular change, but either one is undesirable.
Orders needs to be a List. If you need to preserve some kind of ordering to the list, that needs to be explicit within the data model so that it ends up in the database. Maybe your Order class needs a LineNumber property or something similar. If you do something like that, keep in mind that both the code and the database have to be updated. Search for "Entity Framework migrations" for information about that, and ask a separate question if you get stuck on it.
I'm somewhat new to using LINQ and Entity Framework, and am running into a snag when casting Entity Framework object types to/from objects of a class derived from that object type.
To provide context, I am selecting Survey objects from my Entity Framework DB (records from a Surveys table), for which I have created a derived class that I will actually cast these entity objects to before using them in my application - such that the derived class's signature looks something like:
public sealed class SurveyExtended : Survey
{
public SurveyExtended() : base()
{
// non-base class members initialized here
}
}
And when using LINQ to populate a collection of these objects, I am casting them to the SurveyExtended type using code similar to:
var listOfSurveyExtendedObjects = ( from record in contextFactory.SurveysDbContext.Surveys
select new SurveyExtended()
{
Name = record.Name,
Data = record.Data,
Date = record.Date
}
);
Please note, I know I could use lambda to do the same thing, but I'm just trying to illustrate a concept.
All is well and good, until I actually try and execute DML against SurveysDbContext to do things like UPDATE or DELETE the original record after processing it in my application, such as: contextFactory.SurveysDbContext.Surveys.DeleteObject( surveyExtendedObject );.
Of course this isn't going to work, because I'm manipulating SurveyExtended objects, not the original Survey entity objects, and the ObjectStateManager will throw an InvalidOperationException because the object itself cannot be found. That is to be expected.
I guess what I'm looking for are suggestions and alternative approaches to this scenario. Should I attempt to cast back to Survey objects before trying to DbContext.DeleteObject( record );, or change my approach to this problem entirely? In similar situations, what methods did/do you use, and what benefits/drawbacks do they offer?
The options that come to mind are either cast it back before saving / interacting with EF, or switch to using something like a decorator pattern where the Extended object encapsulates the Survey. Though the second option either means you need to mimic the encapsulated object exposing pass-through accessors (double the code, double the fun) or change referencing code to access SurveyExtended.Survey.Property.
I'm very new to this Entity Framework Object Services Overview (Entity Framework), so forgive me if I use the wrong terminology here.
I'm using the EDMX file to connect to an SQLite database. What I'm trying to do is use the ObjectSet<T> normally, to access a collection of objects from a table in the database. However, I want to additionally store some run-time-only data in the objects in that set. In my case, I have a set of devices stored in the database, but upon startup, I want to mark them as "Connected" or "Disconnected", and keep track of this state throughout execution.
Since the (row) types generated by the EDMX are partial I've added another partial definition, and added my public bool Connected property there. This seems to work, I can set it, and future queries provide objects with the same value that I previously set. The problem is, I don't know a) how it is working, or b) whether I can trust it. These doubts come from the fact that these aren't really collections of objects we're dealing with, right?
Hopefully that made sense, else I can provide more detail.
What you're doing is completely safe.
ObjectSet is still a collection of objects. With a lot magic added underneath.
I am not an expert on the internals but here is how I think it works:
The Entity Framework has a StateTracker hat keeps track of all the entities you're working with.
Every class in your EDMX model is required to have a key. EF is using that key internally so that it loads that specific object only once into memory.
var foo = db.Foos.Single(x => x.Id == 1); // foo with Id 1 is unique (in memory)
var foo2 = db.Foos.Single(x => x.Id == 1); // same instance of foo, but with updated values
var foo3 = db.Foos.Single(x => x.Id == 2) // a new unique instance (Id = 2)
bool sameObject = Object.Equals(foo, foo2); // will return true;
At every select the following happens:
Is an instance of class Foo already tracked/does it already exist?
Yes -> update the properties of the existing instance from the database.
No -> create new instance of class Foo (take values from database)
Of course it can only ever update mapped properties. So the ones you defined in the partial class won't be overwritten.
In case you're going to use code first. There is also the [NotMapped] attribute, that makes sure that the property won't be included in the table if you generate a new database from your code first models.
I hope I could clarify some things for you.
I'm using Entity Framework 4.1. I have a normal model .edmx which maps a Match class to a 'Match' database table and this can be accessed as normal using EF.
However I require custom properties methods for the Match so I extended this using a partial class and I can add my properties etc.
All of this works fine, however I just can't find out how to instantiate an instance of my partial match class by its primary key / id. i.e so I can pass the Id into the constructor and have the object populated with all of its data from the database.
I know we can do the following to populate from calling code:
public Match PopulateforMatchId(int matchId)
{
var match = (from m in _db.Matches
.Include("TeamA")
.Include("TeamB")
.Include("Season")
.Include("Season.Competition")
where m.Match_ID == matchId
select m).FirstOrDefault();
return match;
}
However this is not what I need as this is not self contained within the partial class itself, I need it to populate itself, as other properties in the partial class rely on the object itself having its data in place before they can be calculated.
Anyone have any ideas how i can do this?
Thanks
Kevin
This is wrong way to use Entity framework. Entity framework is not suitable for easy populating existing object. Moreover it demands that entity has internal dependency on the EF context.
How to probably make it work (but I definitely not recommend it):
public Match(int matchId)
{
// You called constructor yourselves = you have unproxied entity without
// dynamic change tracking and without lazy loading
Id = matchId;
// I'm not sure if this is possible in entity constructor but generally it should work
// Get context somewhere - service locator pattern
ObjectContext context = ContextProvider.GetCurrent();
context.Matches.Attach(this);
context.Refresh(RefreshMode.StoreWins, this);
// Now you should have populated Match entity itself but not its navigation properties
// To populate relations you must call separate query for each of them because `Include`
// is possible only when the entity is created and loaded by EF and lazy loading is off
// in this case
context.LoadProperty(this, m => m.TeamA);
context.LoadProperty(this, m => m.TeamB);
Season = (from s in context.Seasons.Include("Competition")
select s).ToList();
}
This is also the example of wrong constructor - constructor should not take such heavy logic. It should be responsibility of some other initialization method.
I'm using a custom named query with NHibernate which I want to return a collection of Person objects. The Person object is not mapped with an NHibernate mapping which means I'm getting the following exception:
System.Collections.Generic.KeyNotFoundException:
The given key was not present in the
dictionary.
It's getting thrown when the Session gets created because it can't find the class name when it calls NHibernate.Cfg.Mappings.GetClass(String className). This is all fairly understandable but I was wondering if there was any way to tell NHibernate to use the class even though I haven't got a mapping for it?
Why don't you use:
query.SetResultTransformer(Transformers.AliasToBean(typeof(Person)));
It will insert data from each column in your query into Person object properties using column alias as a property name.
How can you create a query which would return instances of a type that is not mapped ?
I think Michal has a point here, and maybe you should have a look at projections. (At least, this is what I think you're looking for).
You create a query on some mapped type, and then, you can 'project' that query to a 'DTO'.
In order to do this, you'll have to 'import' your Person class, so that it is known to NHibernate, and you'll have to use a ResultTransformer.
Something like this:
ICriteria crit = session.CreateCriteria (typeof(Person));
// set some filter criteria
crit.SetProjection (Projections.ProjectionList()
.Add (Property("Name"), "Name")
.Add (Property( ... )
);
crit.SetResultTransformer(Transformers.AliasToBean(typeof(PersonView));
return crit.List<PersonView>();
But, this still means you'll have to import the class, so that NHibernate knows about it.
By using the class, NHibernate would basically be guessing about everything involved including which table you meant to use for Person, and the field mappings. NHibernate could probably be hacked to do dynamic binding based on matching the names or something, but the whole idea is to create the mappings from plain old data object to the database fields using the xml files.
If there's not a really good reason not to map the class, simply adding the mapping will give you the best results...
That said, you can't use a named query to directly inject results into an unmapped class. You would need to tell it which columns to put into which fields or in other words, a mapping. ;) However, you can return scalar values from a named query and you could take those object arrays and build your collection manually.
To solve this, I ended up using the TupleToPropertyResultTransformer and providing the list of property values. There are a few limitations to this, the main one being that the SQL query must return the results in the same order as you provide your properties to the TupleToPropertyResultTransformer constructor.
Also the property types are inferred so you need to be careful with decimal columns returning only integer values etc. Apart from that using the TupleToPropertyResultTransformer provided a reasonably easy way to use an SQL query to return a collection of objects without explicitly mapping the objects within NHibernate.