SaveChanges() on my EFv4 POCO context suddenly stopped working. It issues an error "Cannot insert NULL value into column 'postalcode' of table Clients"
Client entity contains a reference to PostCode (properties postalcode, postname) entity.
PostCode reference is not null and so aren't it's properties. My Client entity is referenced from the Document entity.
Here's the code
public void Add(Document instance)
{
// Firm reference
instance.Firm =
(from f in _ctx.Firms
where f.firm_id.Equals(AppState.FirmId)
select f).First();
// Client reference (lazy loading is in place and works)
if (instance.client_id != null)
instance.Client = (from c in _ctx.Clients
where c.client_id.Equals(instance.client_id)
select c).First();
instance.document_id = Guid.NewGuid();
_ctx.Documents.AddObject(instance);
_ctx.Documents.SaveChanges();
}
The thing is, AddObject() works but SaveChanges() fails. I've inspected the Document instance, Client reference and Client's PostCode reference all over and through, all the values are there (which also proves that lazyloading is in place and working) but save doesn't happen.
Looking for ideas what could I've missed..
Firstly, you get the error when you run SaveChanges because that is when it tries to write to the database. Before then it is just in memory.
The error is that postalcode does not allow nulls.
My guess is that in a previous version of the model nulls were allowed. So there are some records without postal codes.
Alternatively, when you retrieve the client the postalcodes are not being retrieved.
In both cases the result is that you are trying to save a postalcode with value null.
Related
I get the error "Cannot insert explicit value for identity column in table 'UserPermission' when IDENTITY_INSERT is set to OFF" trying to insert a record as follows:
dbContext.User.Add(someUser);
dbContext.SaveChanges();
That being said, the User file has the custom class UserPermission as one of its parameters, and someUser's UserPermission is not null and has a set ID parameter. Why does this happen and is it possible to avoid getting this error without having to explicitly add a UserPermissionID foreign key parameter in my User model and setting the UserPermission parameter to null?
Thanks in advance.
This issue typically happens when deserializing entities that have related entities in the object graph then attempting to add them. UserPermission is likely an existing record that in the DB is set up with an identity PK, but EF doesn't appear to recognize that in the entity definition. (I.e. set to DatabaseGenerated(DatabaseGeneratedOption.Identity). If it had been you would most likely be seeing a different problem where a completely new duplicate UserPermission was being created.
If someUser, and it's associated someUser.UserPermission are deserialized entities then you need to do a bit of work to ensure EF is aware that UserPermission is an existing row:
void AddUser(User someUser)
{
var existingPermission = _context.UserPermissions.Local
.SingleOrDefault(x => x.UserPermissionId == someUser.UserPermission.UserPermissionId);
if (existingPermission != null)
someUser.UserPermission = existingPermission;
else
_context.Attach(someUser.UserPermission);
_context.Users.Add(someUser);
_context.SaveChanges();
}
In a nutshell, when working with detached entities that a DbContext may not be tracking, we need to check the Local state for any existing tracked instance for that ID. If we find one, we substitute the detached reference for the tracked one. If we don't find one, we attach the detached one before Adding our user.
This still isn't entirely safe because it assumes that the referenced UserPermission will exist in the database. If for any reason a non-existent UserPermission is sent in (row deleted, or fake data) you will get an exception on Save.
Passing detached entity references around can seem like a simple option at first, but you need to do this for every reference within a detached entity. If you simply call Attach without first checking, it will likely work until you come across a scenario where at runtime it doesn't work because the context happens to already be tracking an instance.
I am new to Breeze.js, but really enjoy it so far. I ran into an issue with updating a database with Breeze.js, when selecting only portion of columns of a model.
When I ran this statement:
$scope.emFac.entityQuery.from('Company');
the company entity matches my EF entity, retrieves all columns, creates entityAspect, and all is working fine when updating database:
However, when I retrieve only portion of corresponding Model's columns, Breeze.js returns anonymous object with specified properties (retrieving data works, but not updating does not), without the entityAspect, which is being used for tracking changes.
Here is the code with select statement:
$scope.emFac.entityQuery.from('Company').select('companyId, displayName');
Is there a way to retrieve only some columns of EF Model columns, and still track changes with Breeze.js, needed for database updates?
As you've discovered, Breeze treats the incoming data as plain objects instead of entities when you use select.
Your choices are:
On the server, Create a CustomerLite or similar object, and have a server endpoint that returns those without the need for select; OR
On the client, get the results from the query and create entities from each object, with status Unchanged
Example of #2:
var entities = [];
em.executeQuery(customerProjectionQuery).then(queryResult => {
queryResult.results.forEach(obj => {
// obj contains values to initialize entity
var entity = em.createEntity(Customer.prototype.entityType, obj, EntityState.Unchanged);
entities.push(entity);
});
})
Either way, you will need to ensure that your saveChanges endpoint on the server can handle saving the truncated Customer objects without wiping out the other fields.
Given the following code, how can I add an element to one of the properties of an entity without knowing its Id and retrieving it from the database?
public async Task BookInPersonVisitAsync(Guid propertyId, DateTime dateTime, CancellationToken token)
{
var entity = new OnBoardingProcessEntity{ ExternalId = propertyId };
DbContext.OnBoardingProcesses.Attach(entity);
entity.OnBoardingProcessVisits.Add(new OnBoardingProcessVisitEntity
{
DateTime = dateTime,
Occurred = false
});
await DbContext.SaveChangesAsync(token);
}
ExternalId is just a guid we use for external reference. This doesnt work cause it does not have the id set, but without hitting the database we cant have it.
With entity framework if you have to reference an entity (referencedEntity) from another entity (entity) you have to know referencedEntity.
Otherwise you can add just add the entity setting the referencedEntity to null.
To know the referencedEntity or you know the Id or you have to retrieve it in some ways (from the database).
In SQL (DML) if (and only if) ExternalId is a candidate key noy nullable you can insert the OnBoardingProcessVisit record with a single roundtrip but the insert statement will contain an inner query.
OnBoardingProcessVisit.OnBoardingProcess_Id = (
SELECT
Id
FROM
OnBoardingProcess
WHERE
ExternalId = #propertyId)
EDIT
No way to generate that query with EF. You can have a look to external components (free and not free, for example EntityFramework Extended but in this case I think that doesn't help).
In this case I probably would try to use standard entity framework features (so 1 roundtrip to retrieve the OnBoardingProcess from the ExternalId).
Then, if the roundtrip is too slow, run the SQL query directly on the database.
About performances (and database consistency) add a unique index on OnBoardingProcess.ExternalId (in every case).
Another suggestion if you decide for the roundtrip.
In your code, the entity will be a proxy. If you don't disable lazy load, using your code you will do one more roundtrip when you will access to property
entity.OnBoardingProcessVisits (in the statement entity.OnBoardingProcessVisits.Add).
So, in this case, disable lazy load or do the same using a different way.
The different way in your case is something like
var onBoardingProcessVisitEntity new OnBoardingProcessVisitEntity
{
DateTime = dateTime,
Occurred = false,
OnBoardingProcess = entity
});
DbContext.OnBoardingProcessVisits.Add(onBoardingProcessVisitEntity);
await DbContext.SaveChangesAsync(token);
I have a rare case where the call of DbSet<T>.Add() changes some properties of other entities that are already in the DbSet<T>. Unfortunately, it happens very rarely, and the only evidence I have are some log files, so I have not yet been able to reproduce it locally.
The behavior is like this:
First, we load some entities from the DbSet using a LINQ query.
Then, some of these entities are changed. No SaveChanges() yet.
Now we add some entities by calling DbSet<T>.Add().
Some of the entities of step 2 are changed in step 3 (one foreign-key property of them is set to null).
Any idea? Is that something that can happen on a EF 6 Code-First model?
The only possibility I can think of is that the DbContext refreshes some data from the database, but we don't want it to do that at this point.
EDIT: The code is currently scattered with log statements, since we have been chasing this bug since weeks. These are the relevant code sections:
// parameter: List<Entry> entriesFromUser
var entriesFromDb = db.Entries
.Where(...)
.OrderBy(...)
.ToList();
var newEntries = MergeEntries(entriesFromDb, entriesFromUser);
var propertyBefore = entriesFromDb[0].MyForeignKeyId;
for (var i = 0; i < newEntries.Count; i++)
{
// make sure that the "new entry" is not a modified one
if (entriesFromDb.Contains(newEntries[i])
{
throw new Exception();
}
db.Entries.Add(newEntries[i]);
}
var propertyAfter = entriesFromDb[0].MyForeignKeyId;
Debug.Assert(propertyBefore == propertyAfter); // <=== fails sometimes
db.SaveChanges();
Please note that the changed foreign key is NOT on the entity being added to the DbSet. It's on an entity that comes from the database, but has been changed in the same transaction.
D'oh. Found the reason. Hope it helps someone else.
We are using Foreign Key Associations, which means that we have both the navigation property entry.MyForeignKey and the Foreign Key property entry.MyForeignKeyId, which has many advantages, but it also means you have to be careful when using sometimes this, sometimes that property.
Turns out we had the following assignment somewhere deep in the code, where all the data of one entry is copied to another one:
entry.MyForeignKeyId = otherEntry.MyForeignKeyId
entry.MyForeignKey = otherEntry.MyForeignKey
However, in many scenarios, you set a foreign key value to an entity's MyForeignKeyId but leave the property MyForeignKey null, because the parent entity is not loaded. This is fine as long as you don't assign null to the entity's MyForeignKey property, because it seems that EF would then set MyForeignKeyId to null too.
So it seems that after our code assigned null to MyForeignKey, the entity lingered in memory with a null MyForeignKey and a non-null MyForeignKeyId. As soon as the next DbSet command was executed (the Add() operation), the DbSet noticed that MyForeignKey has received a null assignment, so DbSet went on and assigned null to MyForeignKeyId too.
I have table A and B
A like : id
name
bid
B like : id
type
in table A has a data record reference with B1,now I want update A reference with B2.
in my unitofwork if I set AutoDetectChangesEnabled = true it's work ok, but I set AutoDetectChangesEnabled = false reason is I want to up speed throw the exception like this:
The changes to the database were committed successfully, but an error occurred while updating the object context. The ObjectContext might be in an inconsistent state. Inner exception message: A referential integrity constraint violation occurred: The property value(s) of 'GoodsKind.goods_kind_id' on one end of a relationship do not match the property value(s) of 'EnrolmentType.goods_kind' on the other end."
how cand i do?
I just had this error as well. The problem for me was that I have a complex type. When I changed the master record (let's say Person) I also wanted to change the complex type List with his contact information(s). So when I tried to save them both in one screen I got this error. Check if you fill all the ids on your screen for the master record and the complex type records. Check if they are posted to the server (if you use in example MVC). You can do this by checking the Bind statement by your MVC action.
The error says that the ID and the object specified doesn't match. This means that you are saying that A has a B with ID=2 but at the same time you have A with an object of type B with ID=5. Because you are working in a disconnected environment, EF doesn't know which one is the correct. To solve this issue you can do one of the following things:
-Get the object from EF, modify it and then save (connected environment).
OR
-Update the IDs manually (update A setting ID=5 because the object B has ID=5).
Always remember that EF tracks changes if it is in a connected environment and the tracking is enabled. If not, it has no clue of the changes you made until it tries to save it in the DB (where the object is compared with the values in the DB). One thing that you can do to manually tell EF that the entity has been modified in a disconnected environment is:
dbContext.Entry(objectA).State = EntityState.Modified;