c# DataContext.SubmitChanges() not updating database - c#

Can someone explain why the following code fails to update the database or what else I can do to troubleshoot?
// *********************************
// People Updates
// *********************************
// In Engr and SoE
EmplIDs = InputList.GetPeopleIds(InputType.Engr | InputType.SoE); // retrieve IDs in tables Engr and SoE
Engr = DB.GetEngrByIds(EmplIDs); // retrieve objects from Engr
SoE = DB.GetSoEByIds(EmplIDs); // retrieve objects from SoE
Batch.Update(SoE, Engr); // update SoE with Engr data
DB.Save(SoE); // persist
// Inside DB repository
public void Save(List<SoE_People> people) {
ChangeSet cs = dc.GetChangeSet();
foreach (SoE_People person in people.Where(p => cs.Updates.Contains(p))) {
person.LastUpdate = DateTime.Now;
}
dc.SubmitChanges();
}
I've checked the following:
people.Count ~ 2500, cs.Updates.Count ~ 200
dc.GetChangeSet.Updates.Count = 0 after calling SubmitChanges()
all updates to the people object are correct. They are visible in the locals window via people and cs.Updates[x]
no exceptions are thrown by dc.SubmitChanges()
setting dc.Log = Console.Out shows no SQL for the SubmitChanges()
a previous section of the code that inserts new records via dc.InsertAllOnSubmit() works fine -> no write permission problem.
manually cutting and pasting data into the SoE_People table works -> no foreign key constraint problem.

Without even looking into the logic you have above, here are some recommendations:
Put everything in a try/catch. How do you know there's no exception being thrown?
dc.SaveChanges() returns an int - number of records that were CRUDed. Capture the return value and check it.

I'm not familiar with DataContext (don't use it), but I'll throw this out there.
If it's like an SqlDataAdapter, did you write/define the SQL text for inserting or updating your records?

You have probably overridden SoE_People update in the datacontext.
There should be a this .ExecuteDynamicUpdate(instance).
Look there maybe you have commented / removed that.
You can take a look here if you don't understand what I mean:
Custom Entity Insert/Update/Delete Method Validation.

Maybe it is not the code, it is the database table.
I had the issue to update the table use that SubmitChanges().
I fixed the problem by giving the table a primary key.

Related

Copying a row from one table to another using LINQ and C#

I have two tables that are pretty much exact clones of one another (identical columns, just different columns set as primary keys). Basically the second table is just for keeping a history of the first table. What I need to do is, when a user updates a record in table 1 I need to insert the original copy of that record into table 2.
I am using a LinqDataSource object and utilizing the LinqDataSource_Updating(object sender, LinqDataSourceUpdateEventArgs e) event so I have access to e.OriginalObject and that will be perfect for inserting the original row in table 2. My problem is that I don't want to have to set every property manually because there are about 50 of them, so I want to use Reflection but am not sure how to properly go about it.
Consider the following code:
INSTRUMENT_DATA_SHEET _original = (INSTRUMENT_DATA_SHEET)e.OriginalObject;
INSTRUMENT_DATA_SHEET_HISTORY _history = new INSTRUMENT_DATA_SHEET_HISTORY();
How can I go about copying all of the _original's property values to _history's? I have tried using the solution from this question, however it isn't working for me. It throws the error:
Property DATE has an incompatible type in E_and_I.INSTRUMENT_DATA_SHEET_HISTORY
My guess is that it's because the DATE column is part of the primary key in table 2, but not table 1. As I said, the only difference between the two tables are the primary keys. Here they are for your reference:
The problem I see is that your History type Date field is DateTime and your Original one is DateTime? (same problem with REV in History, it can't be null). You'll have to decide what happens if there is a null DateTime of Date in your original version. Then you should be able to modify Skeets code (oh dear!) to handle specifically these fields differently then the rest of the fields.
Ok I've managed to figure it out :) Here's what I did:
INSTRUMENT_DATA_SHEET _original = (INSTRUMENT_DATA_SHEET)e.OriginalObject;
INSTRUMENT_DATA_SHEET_HISTORY _history = new INSTRUMENT_DATA_SHEET_HISTORY();
foreach (PropertyInfo pi in _original.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
_history.GetType().GetProperty(pi.Name).SetValue(_history, pi.GetValue(_original, null), null);
}
Not very elegant but it gets the job done!

linq to sql submit changes not working

I have a list view with two colums in wpf Customername and Isvalid.I am using linq to sql to get the data from my sql table.when i am trying to update a value to the table i dont see any changes to the table.
Here is my code when i click on the save button:
try
{
CustomersDataContext dataContext = new CustomersDataContext();
Customer customerRow = MyDataGrid.SelectedItem as Customer;
string m = customerRow.CustomerName;
Customer customer = (from p in dataContext.Customers
where p.CustomerName == customerRow.CustomerName
select p).Single();
customer.Isvalid=false;
dataContext.SubmitChanges();
MessageBox.Show("Row Updated Successfully.");
}
catch (Exception Ex)
{
MessageBox.Show(Ex.Message);
return;
}
I can see that i am able to query the record based on the customername selected but the value is not updating.
I would be glad if some one can point out where am i missing the logic to update the "ISVALID" value to the data base.
Firstly, where's your using(get_datacontext){...} block? You need to dispose of DataContexts when you are done with them!
Anyway...
My guess is that the update statement is generating a where clause that's far too tight, or just plain wrong.
I would be checking the 'Update Check' property of each of the columns in your mapped table in the Linq to Sql designer. The simplest thing to do is to set the primary key column to Always and set all the others to Never. You can also consider setting them to WhenChanged.
The designer's default behaviour is generally to set it to Always for everything; not only does this cause horrible WHERE clauses for updates, but can occasionally also cause problems. Obviously such behaviour is required for proper concurrency checking (i.e. two threads updating the same row); so be aware of that.
Oh, thinking of something else - you can also get this behaviour if your table doesn't have a primary key designated in the designer - make sure one of the columns is.
Finally you can check the SQL being generated when SubmitChanges is called; by attaching a TextWriter to the DataContext.Log property; or equally IntelliTrace in VS2010 will collect all ADO.Net queries that are run if you start with debugging. This is invaluable in debugging why L2S stuff isn't working as expected.
You should Add updated Customer to list of updating customers. I mean before saving changes you should do something like: db.AddToCustomers(customer). AddToCustomers in used in EF, I exactly don't know its equivalent in LINQ.

Committing changes to the database using Entity Framework

I have a situation where I pull data from a table by date. If no data is supplied for a given date I create a record using default values and display it all to the user. When the user is done manipulating the data I need to commit the changes.
So my question is how do I handle in Entity Framework submitting a table where there could be both updates and adds that need to be done. This is in C# using MVC3 and Entity Framework.
So here's what the data might look like to start,
Table A
NAME AGE PHONE_NUM
Jim 25 555-555-5555
Jill 48 555-551-5555
After the users done with the data it could look like this,
Table A
NAME AGE PHONE_NUM
Jim 25 555-555-5555
Jill 28 555-551-5555
Rob 42 555-534-6677
How do I commit these changes? My problem is there are both updates and inserts needed?
I've found some code like this but I don't know if it will work in this case.
For adding rows of data
entities.TABlEA.AddObject(TableOBJECT);
entities.SaveChanges();
or for updating data
entities.TABLEA.Attach(entities.TABLEA.Single(t => t.NAME == TableOBJECT.NAME));
entities.TABLEA.ApplyCurrentValues(TableOBJECT);
entities.SaveChanges();
Will any of this work or do I need to keep track of whats there and what was added?
Ideas?
More or less you already have the solution. You just need to check if your Single call which tries to load the object from the DB has an result or not (use SingleOrDefault instead). If the result is null you need to insert, otherwise update:
foreach (var TableOBJECT in collectionOfYourTableOBJECTsTheUserWorkedWith)
{
var objectInDB = entities.TABLEA
.SingleOrDefault(t => t.NAME == TableOBJECT.NAME);
if (objectInDB != null) // UPDATE
entities.TABLEA.ApplyCurrentValues(TableOBJECT);
else // INSERT
entities.TABLEA.AddObject(TableOBJECT);
}
entities.SaveChanges();
(I'm assuming that NAME is the primary key property of your TableOBJECT entity.)
I think you have to keep track of what is new and what is modified. If you do that, that the two code examples you provided are going to work.
A simple workaround which I used is to check if an entity's primary key property is set to anything. If it is set to a value, then that is an updated object, otherwise it's new.
Another solution would be to use Entity Framework's Self Tracking Entities, but I do not think that's the right direction to go in a web application (maybe it is in a distributed WCF app).

Row not found or changed LINQ C# error on simple statement

First of all, there is no chance that this is a multi-user issue, as I'm working locally on a dev version of the database.
I am getting the not very explanatory Row not found or changed error being thrown when I perform db.SubmitChanges(). If I break the execution just before the SubmitChanges() occurs, I can check in SQL Server Management Studio and the row does exist!
Here's the code for the whole function, just to put it in context for anyone who wants to help, but the problem line is right at the end (line 48).
Update This is a really odd one: the error is caused by updating matchingTrans.Url (see penultimate line of code). Commenting out this line doesn't throw the error - even if the matchingTrans.Title still gets updated.
private static void MenuItemUpdate(int languageId, NavigationItem item)
{
using (var db = DataContextFactory.Create<MyDataContext>())
{
// Select existing menu item from database.
var dbItem =
(from i in db.MenuItems
where i.Id == item.Id
select i).Single();
// Obtain ID of link type.
dbItem.FkLinkTypeId = GetLinkTypeByName(
Enum.GetName(typeof (NavigationItemLinkType), item.LinkType)).Id;
// Update the Link field with what is given.
dbItem.Link = item.Link;
db.SubmitChanges();
// Item already exists and needs editing.
// Get associated translations.
var trans =
from t in db.MenuItemTranslations
where t.FkMenuItemId == item.Id
select t;
// If translation exists for given language, edit it.
var matchingTrans =
(from t in trans
where t.FkLanguageId == languageId
select t).SingleOrDefault();
if (matchingTrans == null)
{
// No matching translation - add one.
var newDbTrans = new MenuItemTranslation
{
FkMenuItemId = item.Id,
FkLanguageId = languageId,
Title = item.Title,
Url = item.FriendlyUrl
};
db.MenuItemTranslations.InsertOnSubmit(newDbTrans);
db.SubmitChanges();
}
else
{
// Matching translation - edit it.
matchingTrans.Title = item.Title;
matchingTrans.Url = item.FriendlyUrl;
db.SubmitChanges();
// WTF ERROR: Row not found or changed.
}
}
}
Looking at the SQL Profiler output, it helped me figure out the answer to this. There was a bad piece of SQL being generated which ended with WHERE 0 = 1 ... an obvious error.
It turns out that the field had simply been changed to allow nulls by another developer, and the Linq-to-SQL file hadn't been updated accordingly.
In short, if the Row not found or changed error message appears to be generated for no reason, make sure your database schema exactly matches your .dbml file else you'll get this error message on any fields that have slightly differing schemas.
Take a look at the connection property "No Count" at sql server server level
1. Right click on Sql server connection in Object Explorer -->Property
2. Go to Connection Tab/Page
3. Look for the Default connection option "no count"
4. Make sure this option is not checked.
Another possibility that I've found to add to the excellent list of answers here:
When using a not-nullable column in a database - then mapping that to a datatype that is intrinsically nullable (in this example DB type is LONG BLOB NOT NULL mapped to a byte array in c#) you can end up in a situation where updating the database with the exact same byte array causes this error to be thrown.
Example: You have a website that allows the user to upload an image to the database. Your table has a blob (image in sql server, whatever) that is not nullable. The user chooses to update the record with the exact same image that is already there. The update check will fail. I fixed this by first doing a .SequenceEqual() check and then only calling .SubmitChanges() on the context object if the incoming byte array was not equal to the existing one.
I had this issue even when the database schema and dbml matched exactly. The issue was I was trying to change an entity and insert entities in a single SubmitChanges statement. I fixed it by doing SubmitChanges on each operation instead of all at once.
This was all in a transaction scope so that may have something to do with it but I'm not sure.

Linq-to-Sql SubmitChanges not updating fields ... why?

I posted this question yesterday evening, which has led me to discover a huge problem!
I have a decimal column in my database called Units, anytime I set the value of the column to a NON ZERO, and SubmitChanges the column updates with the new value. If I try to set the value of the column to ZERO, the SubmitChanges does not update the column.
data.Units = this.ReadProperty<decimal>(UnitsProperty);
data.UnitPrice = this.ReadProperty<decimal>(UnitPriceProperty);
data.Price = this.ReadProperty<decimal>(PriceProperty);
I've taken a look at the DataContext log and I can see that the field with the ZERO value is not included in the query. Even if I try to hard code the change Linq ignores it.
data.Units = 0;
data.UnitPrice = 0;
data.Price = 0;
Needless to say this is killing me! Any ideas why this happening?
Solution
I figured out my problem with the help of the SO community. My problem was being caused by the fact when I created my entity to attach, the default value of the column was set to zero, so when it tried to assign the value to zero ... LinqToSql says hey ... nothing changed, so I am not updating the value.
What I am doing now ... just to make it work is the following:
ctx.DataContext.InvoiceItems.Attach(data, true);
That seems to force all the values to write themselves to the database. This works for now.
I have tried to reproduce this with a the following code, but for me it works.
using (DataClasses1DataContext ctx = new DataClasses1DataContext())
{
var obj = ctx.DecimalColumnTables.First();
Debug.Assert(obj.B != 0);
obj.B = 0;
ctx.SubmitChanges();
}
So I think there must be something special in your domain that causes this. I suggest you to create a such simple repro with your domain model and see what happens.
LINQ to SQL ignores updates to the current value, so if the field was already zero, you may not see any updates.
Off: The OR/M you use is LINQ to SQL. LINQ is the name of the querying capability in .NET, but LINQ does not define nor implement any update logic. So the issue relates to LINQ to SQL, not LINQ.
Obvious question, but are you sure the column is mapped in the dbml / mapping file?
Also - is it a calculated column? (i.e. price => units * unitprice)
I figured out my problem with the help of the SO community. My problem was being caused by the fact when I created my entity to attach, the default value of the column was set to zero, so when it tried to assign the value to zero ... LinqToSql says hey ... nothing changed, so I am not updating the value.
What I am doing now ... just to make it work is the following:
ctx.DataContext.InvoiceItems.Attach(data, true);
That seems to force all the values to write themselves to the database. This works for now.
Some more information ... I figured out my problem ... it's more of a lack of understanding about LinqToSql ... where I am doing:
private void Child_Update(Invoice parent)
{
using (var ctx = Csla.Data.ContextManager
.GetManager(Database.ApplicationConnection, false))
{
var data = new Gimli.Data.InvoiceItem()
{
InvoiceItemId = ReadProperty(InvoiceItemIdProperty)
};
ctx.DataContext.InvoiceItems.Attach(data);
if (this.IsSelfDirty)
{
// Update properties
}
}
}
I thought this would load the original values ... what happens is that it creates a new object with default values ... empty values, like 0 for decimals, Guid.Empty for uniqueidentifiers and so on.
So when it updates the properties it sees the Units already as 0 and it sets it to zero. Well LinqToSql doesn't recognize this as a change so it doesn't up date the field. So what I have had to do is the following:
ctx.DataContext.InvoiceItems.Attach(data, true);
Now all the modifications are generated in the update statement whether there is really a change or not. This works ... seems a bit hackish!
The correct answer is as many pointed out to use the special overload of Attach which accepts a boolean parameter to consider it as modified, (make the mistake of using another overload and it simply won't work):
ctx.DataContext.InvoiceItems.Attach(data, true);
Note however that you still might need to have a "Version" column in the table of type "timestamp".
I had this problem and all the suggestions I'd seen didn't apply or work.
But I found I had made a very simple mistake!
When updating the property I was actually calling a custom Set method (because there were other things that needed to be changed in response to the main property in question).
After hours of head scratching I noticed that my Set method was updating the private member not the public property, i.e. this._Walking = value;
All I had to do was change this to this.Walking = value; and it all started to work!

Categories

Resources