Why am I getting a "Unable to update the EntitySet because it has a DefiningQuery..." exception when trying to update a model in Entity Framework? - asp.net-mvc

While updating with the help of LINQ to SQL using Entity Framework, an exception is thrown.
System.Data.UpdateException: Unable to update the EntitySet 't_emp' because it has
a DefiningQuery and no <UpdateFunction> element exists in the
<ModificationFunctionMapping>
The code for update is :
public void Updateall()
{
try
{
var tb = (from p in _te.t_emp
where p.id == "1"
select p).FirstOrDefault();
tb.ename = "jack";
_te.ApplyPropertyChanges(tb.EntityKey.EntitySetName, tb);
_te.SaveChanges(true);
}
catch(Exception e)
{
}
}
Why am I getting this error?

The problem was in the table structure. To avoid the error we have to make one primary key in the table. After that, update the edmx. The problem will be fixed

Three things:
Don't catch exceptions you can't handle. You're catching every exception possible, and then doing nothing with it (except swallowing it). That's a Bad Thing™ Do you really want to silently do nothing if anything goes wrong? That leads to corrupted state that's hard to debug. Not good.
Linq to SQL is an ORM, as is Entity Framework. You may be using LINQ to update the objects, but you're not using Linq to SQL, you're using Entity Framework (Linq to Entities).
Have you tried the solution outlined here? The exception you posted is somewhat cut off, so I can't be sure it's exactly the same (please update your post if it isn't), and if it is the same, can you comment on whether or not the following works for you?
"[..] Entity Framework doesn't know whether a given view is updatable
or not, so it adds the <DefiningQuery> element in order to safeguard
against having the framework attempt to generate queries against a
non-updatable view.
If your view is updatable you can simply remove the <DefiningQuery>
element from the EntitySet definition for your view inside of the
StorageModel section of your .edmx, and the normal update processing
will work as with any other table.
If your view is not updatable, you will have to provide the update
logic yourself through a "Modification Function Mapping". The
Modification Function Mapping calls a function defined in the
StorageModel section of your .edmx. That Function may contain the
name and arguments to a stored procedure in your database, or you can
use a "defining command" in order to write the insert, update, or
delete statement directly in the function definition within the
StorageModel section of your .edmx." (Emphasis mine, post formatted for clarity and for Stack Overflow)
(Source: "Mike" on MSDN)

But You can Set primary Key in Model if use MVC Asp.net
Just Open model.edmx in your table ,go to your field property and set Entity Key = True

Related

Using Umbraco Forms to edit data

I would like to use Umbraco Forms to not only insert data but to edit it as well. So far when I want to edit a record I am passing in the form guid and the record id via querystring and populating the correct data in the fields.
So far so good.
I am then hooking in to the Umbraco.Forms.Data.Storage.RecordStorage.RecordInserting event successfully like so
void RecordStorage_RecordInserting(object sender, Umbraco.Forms.Core.RecordEventArgs e)
{
var ms = (Umbraco.Forms.Data.Storage.RecordStorage)sender;
if(this record exists){
ms.UpdateRecord(e.Record, e.Form);
}
}
However when I try to submit an edited record, and the ms.RecordUpdate(e.Record, e.Form) line runs I get this error
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_UFRecordDataString_UFRecordFields_Key". The conflict occurred in database "UmbracoPlay", table "dbo.UFRecordFields", column 'Key'.
The statement has been terminated.
I can't delete the old record and then insert a new record because it will re raise the same event everytime I call ms.InsertRecord
What am I missing?
How can I use Umbraco Forms to edit existing data?
I couldn't see a fix for this bug- it appears as though the UpdateRecord method actually tries to insert all UFRecordField objects a second time rather than updating the existing values ( or the existing field values ) resulting in this key violation.
If you really need to work around this - as I did - then one thing that works ( but leaves you with somewhat more fragmented primary keys ) is simply to remove and then reinsert the form data:
var ms = (Umbraco.Forms.Data.Storage.RecordStorage)sender;
if(this record exists){
ms.DeleteRecord(e.Record, e.Form);
ms.InsertRecord(e.Record, e.Form);
}
An untidy solution, but seemingly effective.

Hydrating Database

I am new to learning and understanding how Hydration works, just wanted to point that out first. I'm currently able to Hydrate Select and Insert queries without any problems.
I am currently stuck on trying to Hydrate Update queries now. In my entity I have setup the get/set options for each type of column in my database. I've found that the ObjectProperty() Hydrator works best for my situation too.
However whenever I try to update only a set number of columns and extract via the hydrator I am getting errors because all the other options are not set and are returning null values. I do not need to update everything for a particular row, just a few columns.
For example in my DB Table I may have:
name
phone_number
email_address
But I only need to update the phone_number.
$entity_passport = $this->getEntityPassport();
$entity_passport->setPrimaryPhone('5551239876');
$this->getTablePassport()->update($this->getHydrator()->extract($entity_passport), array(
'employeeid' => '1'
));
This returns an error because setName() and setEmailAddress() are not included in this update and the query returns that the values cannot be null. But clearly when you look at the DB Table, there is data already there. The data that is there does not need to be changed either, only in this example does the PrimaryPhone() number.
I've been looking and reading documentation all over the place but I cannot find anything that would explain what I am doing wrong. I should note that I am only using Zend\Db (Not Doctrine).
I'm assuming I've missed something someplace due to my lack of knowledge with this new feature I'm trying to understand.
Perhaps you don't Hydrate Update queries... I'm sort of lost / confused. Any help would be appreciated. Thank you!
I think you're having a fundamental misconception of hydration. A hydrator simply populates an entity object from data (hydrate) and extracts data from an entity object (extract). So there are no separate hydrators for different types of queries.
In your update example you should first retrieve the complete entity object ($entity_passport) and then pass it to the TableGateway's update method. You would retrieve the entity by employeeid, since that's the condition you're using to update. So something like this:
$entity_passport = $passportMapper->findByEmployeeId(1);
$entity_passport->setPrimaryPhone('5551239876');
$this->getTablePassport()->update($this->getHydrator()->extract($entity_passport), array(
'employeeid' => $entity_passport->getId()
));
This is assuming you have some sort of mapper layer. Otherwise you could use your passport TableGateway (I assume that's what getTablePassport() returns, no?).
Otherwise, if you think retrieving the object is too much overhead and you just want to run the query you could use just a \Zend\Db\Sql\Sql object, ie:
$sql = new \Zend\Db\Sql\Sql($dbAdapter);
$update = $sql->update('passport')
->set(array('primary_phone' => $entity_passport->getPrimaryPhone()))
->where(array('employeeid' => $employeeId));
Edit:
Maybe it was a mistake to bring up the mapper, because it may cause more confusion. You could simply use your TableGateway to retrieve the entity object and then hydrate the returned row:
$rows = $this->getTablePassport()->select(array('employeeid' => 1));
$entity_passport = $this->getHydrator($rows->current());
[...]
Edit 2:
I checked your gist and I noticed a few things, so here we go:
I see that your getTablePassport indeed does return an object which is a subclass of TableGateway. You have already set up this class for it to use a HydratingResultset. This means you don't need to do any manual hydrating when retrieving objects using the gateway.
You also already implemented a Search method in that same class, so why not just use that? However I would change that method, because right now you're using LIKE for every single column. Not only is it very inefficient, but it will also give you wrong results, for example on the id column.
If you were to fix that method then you can simply call it in the Service object:
$this->getTablePassport->Search(array('employeeid' => 1));
Otherwise you could just implement a separate method in that tablegateway class, such as
public function findByEmployeeId($employeeId)
{
return $tableGateway->select(array('employeeid' => $employeeId));
}
This should already return an array of entities (or one in this specific case). P.S. make sure to debug and check what is actually being returned when you retrieve the entity. So print_r the entity you get back from the PassportTable before trying the update. You first have to make sure the retrieval code works well.

which is the difference betwwen this two ways to refresh the dbContext?

I am using EF 4.4 and I would like to update many entities, but some other user can modified many of the entities that the first user is modified. So I get a concurrency exception. Other case is that the first user tries to add many new registers and other user added some of them meanwhile. So I have an exception that exists some of the registers (unique constraint).
I would like to ensure that the first user finish his operation add only the registers that does no exists yet (add all his entities except the entities that are added by the second user).
To do that, I need to update the entities in my dbContext so I see that there at least two options.
First, in the catch when I capture the update exception, I can do:
ex.Entries.Single().Reload();
The second option is:
myContext.Entry<MyTable>(instance).Reload();
I guess that the second option only refreshes the entity that I use as parameter, but if the problem is that I need to refresh many entities, how can I do that?
What really does the first option, Single().Reload?
When you do
ex.Entries.Single().Reload();
you are sure that the offending entity is refreshed. What is does is taking the one and only (Single) entity from the DbUpdateConcurrencyException.Entries that could not be saved to the database (in case of a concurrency exception this is always exactly one).
When you do
myContext.Entry(instance).Reload();
You are not sure that you refresh the right entity unless you know that only one entity had changes before SaveChanges was called. If you save an entity with child entities any one of them can cause a concurrency problem.
In EF 6.x (6.1.3), below code will let you find all the changes; the way you asked in your question!
try
{
var listOfRefreshedObj = db.ChangeTracker.Entries().Select(x => x.Entity).ToList();
var objContext = ((IObjectContextAdapter)your_db_context).ObjectContext;
objContext.Refresh(System.Data.Entity.Core.Objects.RefreshMode.ClientWins, listOfRefreshedObj);
await db.Entry(<yourentity>).ReloadAsync();
return Content(HttpStatusCode.<code>, "<outputmessage>"); ;
}
catch (Exception e)
{
return Content(HttpStatusCode.<code>, "<exception>");
}
Explaination:
Query Entries in the ChangeTracker and store them in a list
var listOfRefreshedObj = db.ChangeTracker.Entries().Select(x => x.Entity).ToList();
Next is to refresh the context. In some cases (row is removed etc.), this will throw an exception which you can catch. RefreshMode.ClientWins tells EF to accept all client units as modified when next update occurs. In some cases, you might want to prompt the users with the changes and let them decide. RefreshMode Enumeration. An example is here ObjectContext.Refresh Method Example
objContext.Refresh(System.Data.Entity.Core.Objects.RefreshMode.ClientWins, listOfRefreshedObj);
You're probably doing this whole thing after you receive DbUpdateConcurrencyException anyways!

EF - generic "AddOrUpdate" method suddenly breaks

I am using Entity Framework 4 (database-first approach) in my ASP.NET 4.0 Webforms app.
What I'm basically doing is fetching the entity to be edited from my ObjectContext, and displaying the fields the user should enter data into (or modify existing data) on a web form.
When time comes to store the data back, I'm reading out the values from the web form, building up a new Entity instance, and then I have a generic method called AddOrUpdate that detects whether this is a new entity (so it needs to insert it), or if it's an existing one (so it needs to update the existing data).
My method using the EntityKey and checks to see if the object context already knows about this object - very similar to what Cesar de la Torre of Microsoft shows here in his blog post:
public static void AddOrUpdate(ObjectContext context, EntityObject objectDetached)
{
if (objectDetached.EntityState == EntityState.Detached)
{
object currentEntityInDb = null;
if (context.TryGetObjectByKey(objectDetached.EntityKey, out currentEntityInDb))
{
// attach and update the existing entity
}
else
{
// insert new entity into entity set
context.AddObject(objectDetached.EntityKey.EntitySetName, objectDetached);
}
}
}
This worked just fine - for the longest time. But today, suddenly, out of the blue, I keep getting exceptions like this on the context.TryGetObjectByKey statement:
System.InvalidOperationException: Object mapping could not be found for Type with identity 'MyEntityType'
I cannot remember having changed anything in this core code at all - and the entity type is defined, the ID value that's stored in the EntityKey does indeed exist in the database... everything should be fine - but it keeps failing on me...
What on earth happened here??
I did find a few blog and forum posts on the topic, but none could really enlighten me or help me fix the issue. I must have messed up something - bad - but I really cannot see the forest for the trees - any hints?
Generally this sort of issue happens when EF cant find the assembly that has the type. With out seeing the full exception is difficult to figure out exactly but it seems your recent changes and the way you are using EF seems to be the cause.
EF ususally picks the type directly from the type itself when it has to access it using ObjectSet on the context. In the other cases where the type is not available from the context of the call it looks at the calling assembly and any dll's referenced by the calling assembly. Id it cant find it it throws the error message.
You can use the LoadFromAssembly method in the MetadataWorkspace of the context.
ObjectContext.MetadataWorkspace.LoadFromAssembly(assembly).
This way EF will know where to look for your types.

Cannot insert new Employee entity using InsertOnSubmit()

I'm facing this exception An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported. when I try to insert a new entity into my Employees table (the master one).
There is a relationship between the master Employees table and the details Orders table, and I'm sure that the relationship between these two tables (and specifically Employee.Orders EntitySet) is the cause of the problem since when I removed the relationship, it returns back to insert into Employees table with no problems.
When I searched for the problem, there was this blog post which I tried to implement but my case is a different than the one in the blog post in these items:
He faces the exception when tries to update (while I try to insert).
The tables architecture is different.
how can I solve this problem?
Here's the insertion code:
Employee emp = new Employee();
emp.Name = empName; // empName is a local variable
// What should I default emp.Orders to?
dc.Employees.InsertOnSubmit(emp);
dc.SubmitChanges();
P.S: My DataContext is defined on class-level in my repository and the exception is being thrown when I call dc.SubmitChanges();. and I didn't Attach any object why does it say that?
Here is an article explaining what you need to do using the Attach and Detach methods:
http://www.codeproject.com/KB/linq/linq-to-sql-detach.aspx
I am guessing it is trying to save something else besides just the employee object or you aren't showing us the full code in your repository. When you instantiate your DataContext object (dc) try setting DeferredLoadingEnabled = false, and ObjectTrackingEnabled = false and see if it works. If it does, try watching the SQL code in SQL Server Profiler and see if it is modifying other objects that may have came from a different context like the message says.
var dc = new MyDataContext()
{
DeferredLoadingEnabled = false,
ObjectTrackingEnabled = false
};
My bet is on the primary key.
Are you sure the primary key is also set on auto increment?
Did you
try changing the name, does it work then?
What happens if you remove
all rows from your DB? can you insert one then?

Resources