I've a strange problem using EF1.0... my problem happenin' only during a creation and I didn't find anything on many forum's thread.
> System.InvalidOperationException: The source query for this EntityCollection or EntityReference cannot be returned when the related object is in either an added state or a detached state and was not originally retrieved using the NoTracking merge option.
at System.Data.Objects.DataClasses.RelatedEnd.CreateSourceQuery[TEntity](MergeOption mergeOption)
at System.Data.Objects.DataClasses.EntityCollection`1.CreateSourceQuery()
at Microsoft.Data.EFLazyLoading.LazyEntityCollection`1.CreateSourceQuery()
at Microsoft.Data.EFLazyLoading.LazyEntityCollection`1.LoadStubs()
at mptradModel.ContextObjects.ChansonWrapper.AttachEntities(Chanson chanson, ChansonRequest request) in (SolutionDir)\ProjectWrapper\ContextObjects\ChansonWrapper.cs:line 115
What is the real problem? I happens when I tried to add an Entity to another entity's list during a command creation.
I.E.: aCommand.Songs.Add(new Song() { Name = "SongName" });
Thank to you guys and sorry for my english ; Im from Quebec and usualy talk french!
UPDATE #1
My line #115 in chansonwrapper (which mean "songwrapper") :
aCommand.Songs.Add(new Song() { Name = "SongName" });
UPDATE #2
Sorry, I were trying to simplify the code to write but I think its just more confusing so here is my real code :
SongWrapper songWrapper = new SongWrapper(this.m_Context);
Song song = songWrapper.Load(request.SongId);
aCommand.Songs.Add(song);
The this.m_Context for my songWrapper ensure that my song returned in in the same context of my "aCommand" or other entity that i could load later/before. This part were alrealy tested so we know it works. One things have changed, is that we moved to "LazyLoading" what we were not using before. More weird, the update works fine! Help meee :oP!
This is certainly not EF 1.0. It must be 4.0 beta. I think it may be a bug in lazy loading. You're doing (from a back revision of your question) if( aCommand.songs.Count() > 0. For an entity in the added state, this should not try to lazily load the songs. But it seems to be trying to do just that. My only suggestion is to work around the bug via something like:
if ((aCommand.EntityState != EntityState.Added)
&& (aCommand.songs.Count() > 0))
...which is a bit kludgy, or turn lazy loading off for this. If you can boil this down to a reproducible test case, you might report it to Microsoft Connect.
By the way, you should generally prefer:
if (aCommand.songs.Any())
... to Count() > 0 as it's more efficient and readable. But that's irrelevant here.
Related
I have a collection of users that I'm trying to read from the database, but for some reason some strange behavior takes place that I can't really figure out. Hopefully, somebody can suggest or help me find the root of this problem.
So basically, what happens is that whenever I call this code in my HomeController.cs:
var users = await _database.GetCollection<User>("ApplicationUsers").FindAsync(_ => true);
var userList = users.ToList();
it only populates userList partially, meaning only the ID and ConcurrencyStamp properties get filled, but the other properties always end up being null (as seen in: https://i.imgur.com/RTF8ljL.png)
But whenever I add this line right after the database connection initialization in the Startup.cs:
database.GetCollection<User>("ApplicationUsers");
Then suddenly userList does get populated with all the other information (as seen in https://i.imgur.com/f5IV7fh.png)
So in order for it to work, I have to get the collection right after the connection gets initialized which I'm not really fond of, because I don't have to do this for other collections. So my mongo connection code would have to look like this in the Startup.cs:
var mongoUrl = new MongoUrl(config.GetSection("DatabaseSettings:ConnectionString").Value);
var mongoClientSettings = MongoClientSettings.FromUrl(mongoUrl);
mongoClientSettings.ClusterConfigurator = cb => ConfigureCluster(cb);
var client = new MongoClient(mongoClientSettings);
var database = client.GetDatabase(config.GetSection("DatabaseSettings:DatabaseName").Value);
database.GetCollection<User>("ApplicationUsers"); // TODO: This is needed just to let Mongo Driver know to which class to deserialize this collection
services.AddSingleton<IMongoDatabase>(database);
var pack = new ConventionPack()
{
new CamelCaseElementNameConvention(),
new IgnoreExtraElementsConvention(true),
new DictionaryRepresentationConvention(DictionaryRepresentation.ArrayOfArrays)
};
ConventionRegistry.Register("DatabaseConventions", pack, t => true);
I'm guessing something happens between the execution of Startup.cs and HomeController.cs that causes the deserialization to mess up?
Update:
The same behavior seems to happen on a clean project, the only nuget packages I installed are the official mongodb driver and AspNetCore.Identity.Mongo by Matteo Fabbri. This strange deserialize behavior does not happen when I use getCollection for other classes. The problem lies with ApplicationUser which extends from MongoUser (a class made available by the AspNetCore.Identity.Mongo library)
Update 2:
Turns out that MongoUser class from the AspNetCore.Identity.Mongo library is allergic to the ConventionPack that was registered. I tested this by getting the collection before and after the registration of the database conventions. Now finding a proper solution for this.
Update 3:
Also I found out that documents are saved with properties named in Upper Camel Case, which could be the cause for mongodb driver's confusion. It seems that the conventions set to save them in CamelCase is being ignored for this particular class (ApplicationUser).
I managed to solve the problem. The issue was the order of code execution. The convention pack was registered after MongoIdentity and the database was initialized. During the initialization of MongoIdentity and the Database, the ApplicationUser was configured to not have the CamelCaseElementNameConvention in the pack, which led to the class being saved in UpperCamelCase and therefore cause confusion when retrieving the collection when the registered ConventionPack was active.
For whoever struggles with strange behavior where you may think your code should work, remember that the order of code execution is very important and could very well be the cause of the behavior. Good luck to y'all!
I'm having an odd little problem with MVC2. I am perorming some CRUD tasks, and I can Create records in the database just fine. But when I go to update a record with the following code nothing seems to happen to the database:
EntityModelConnection entityModelConnection = new EntityModelConnection ();
try {
OrderLogic orderLogic= new OrderLogic ();
EntityObject_Orders orderToUpdate = OrderLogic.GetOrderByID(1);
orderToUpdate.Name = "Laptop";
EntityModelConnection.SaveChanges(); }
My code isn't using names like these, they are just renamed for clarity :)
When I run over this code, no errors are thrown and the correct single record is returned from OrderLogic.GetOrdersByID, but nothing seems to update in the database.
It's a bit hard to find guides on this since most people are using UpdateModel in the controller and I'm doing my logic far from that location, so I can't (seem) to use that feature.
Any thoughts on what I might be missing? Is there something strange about MVC when it comes to updating records I might be missing?
I'm going for a coffee to refresh my brain :)
MVC or no MVC should have no effect on your data layer. I suspect that your order isn't being updated because it either isn't marked as being changed in the persistance layer or you're not getting it from the same persistance layer object that you're saving changes in. How is it that the connection you're creating and saving from is provided to the OrderLogic object to retrieve the EntityObject_Orders object?
It looks like your Order instance came from a different entity connection.
I'm new to NHibernate, but have managed to get it all running fine for my latest project. But now I've reached the inevitable performance problem where I need to get beyond the abstraction to fix it.
I've created a nunit test to isolate the method that takes a long time. But first a quick overview of my domain model is probably a good idea:
I have a 'PmqccForm' which is an object that has a 'Project' object, which contains Name, Number etc and it also has a 'Questions' object, which is a class that itself contains properties for various different 'Question' objects. There is a JobVelocityQuestion object which itself has an answer and some other properties, and a whole bunch of similar Question objects.
This is what I'm talking about with my PmqccForm having a Questions object
This is the questions part of the model:
The key point is that I want to be able to type
form.Questions.JobVelocityQuestion
as there is always exactly 1 JobVelocityQuestion for each PmqccForm, its the same for all the other questions. These are C# properties on the Questions object which is just a holding place for them.
Now, the method that is causing me issues is this:
public IEnumerable<PmqccForm> GetPmqccFormsByUser(StaffMember staffMember)
{
ISession session = NHibernateSessionManager.Instance.GetSession();
ICriteria criteria = session.CreateCriteria(typeof(PmqccForm));
criteria.CreateAlias("Project", "Project");
criteria.Add(Expression.Eq("Project.ProjectLeader", staffMember));
criteria.Add(Expression.Eq("Project.IsArchived", false));
return criteria.List<PmqccForm>();
}
A look in my console from the Nunit test which just runs this method shows that there is nearly 2000 sql queries being processsed!
http://rodhowarth.com/otherstorage/queries.txt is the console log.
The thing is, at this stage I just want the form object, the actual questions can be accessed on a need to know basis. I thought that NHibernate was meant to be able to do this?
Here is my mapping file:
http://rodhowarth.com/otherstorage/hibernatemapping.txt
Can anyone hint me as to what I'm missing? or a way to optimize what I'm doing in relation to NHibernate?
What if I made the questions a collection, and then made the properties loop through this collection and return the correct one. Would this be better optimization from nhibernates point of view?
Just try to add fetch="subselect" to the mapping file for Questions component and see if this solves the issue with multiple selects to that table - you should now see one 2nd select instead of hundreds separate queries, e.g.
<component name="Questions" insert="true" update="true" class="PmqccDomain.DomainObjects.Questions" fetch="subselect">
See for more info - Improving performance
How would you do this (pseudo code): product1.Orders.AddRange(product2.Orders);
However, the function "AddRange" does not exist, so how would you copy all items in the EntityCollection "Orders" from product2 to product1?
Should be simple, but it is not...
The problem is deeper than you think.
Your foreach attempt fails, because when you call product1.Orders.Add, the entity gets removed from product2.Orders, thus rendering the existing enumerator invalid, which causes the exception you see.
So why does entity get removed from produc2? Well, seems quite simple: because Order can only belong to one product at a time. The Entity Framework takes care of data integrity by enforcing rules like this.
If I understand correctly, your aim here is to actually copy the orders from one product to another, am I correct?
If so, then you have to explicitly create a copy of each order inside your foreach loop, and then add that copy to product1.
For some reason that is rather obscure to me, there is no automated way to create a copy of an entity. Therefore, you pretty much have to manually copy all Order's properties, one by one. You can make the code look somewhat more neat by incorporating this logic into the Order class itself - create a method named Clone() that would copy all properties. Be sure, though, not to copy the "owner product reference" property, because your whole point is to give it another owner product, isn't it?
Anyway, do not hesitate to ask more questions if something is unclear. And good luck.
Fyodor
Based on the previous two answers, I came up with the following working solution:
public static void AddRange<T>(this EntityCollection<T> destinationEntityCollection,
EntityCollection<T> sourceEntityCollection) where T : class
{
var array = new T[sourceEntityCollection.Count()];
sourceEntityCollection.CopyTo(array,0);
foreach (var entity in array)
{
destinationEntityCollection.Add(entity);
}
}
Yes, the usual collection related functions are not there.
But,
1. Did you check CopyTo method?
2. Do you find any problem with using the iterator? You know, GetEnumerator, go through the collection and copy the entities?
The above two can solve your problems. But, I'm sure in .NET 3.0+ there would be compact solutions.
My answers are related to .NET 2.0
im using subsonic 3.0.0.3 activerecord and everything is fine and i get no error but when i update a database, it never seems to actually happen, can anyone spot anything i am missing here?! ta
code:
var myquote = createNewQuote();
var gross = 36.00;
myquote.totalcost = gross; // set the new value in my model
UpdateModel(myquote); // update the model, something to do with dirty columns??
if(ModelState.IsValid) // check to make sure i have no errors in my model after changing it
myquote.Update(); // command that is supposed to update the database????
i have put a break point on UpdateModel and looked into the model and the value is in the model as directed, i get no error and modelstate is valid too, but when i look into the database the totalcost has not actually been changed for that record????
i have also tried .Save() but this too does not seem to change anything ?????
am a little puzzled
not sure if this fixes your problem but I know there a few bugs fixed here that helped me out with a few isssues I was having.
Goto: http://github.com/subsonic/SubSonic-3.0/tree/master
There was a bug introduced in 3.0.0.1 that I removed quickly with 3.0.0.2 that inhibited updates in certain scenarios with ActiveRecord. Our current version is 3.0.0.3 - you should update.
Subsonic is not yet stable.. You will end up wasting your time googling around.. (peace!)
to solve your problem try this.
myquote.SetIsLoaded(true);