I am trying to find a neater way to save table/column updates. I have an object representing the current order table entry and an object with all updated values. I want to compare each variable with matching names in each object and save the update to the database if different.
The current way I am doing this (which I know is badly written) is as follows:
if (currentOrder.Comment != editedOrder.Comment)
{
createOrderUpdateRecord("Comment", currentOrder.Comment.ToString(), editedOrder.Comment.ToString(), OrderID);
currentOrder.Comment = editedOrder.Comment ;
anyChangesMade = true;
}
if (currentOrder.CustomerName != editedOrder.CustomerName )
{
createOrderUpdateRecord("CustomerName ", currentOrder.CustomerName .ToString(), editedOrder.CustomerName .ToString(), OrderID);
currentOrder.CustomerName = editedOrder.CustomerName ;
anyChangesMade = true;
}
and then in the createOrderUpdateRecord method, I save the information to an edits table.
In case anyones interested I ended up using the tracker enabled db context library alongside entity framework to track changes to table fields, which did the job perfectly
In case you are using the normal .NET Winforms DataGridView when you refer to table/column-updates:
There is an event called "CellValueChanged". Also there is "CellEndEdit". If you subscribe to either of those, you could set a "changed"-variable to true to track if you must update the value in the database.
Related
I am a newbie to Cassandra and my current project called for me to create a table with the following columns:
id uuid PRIMARY KEY,
connections list<text>,
username text
I am using Cassandra's IMapper interface to handle my CRUD operations. While I found documentation that describes how to use the Mapping component for basic operations here:
http://docs.datastax.com/en/developer/csharp-driver/2.5/csharp-driver/reference/mapperComponent.html
I could not find documentation that outlines how to add and remove items from the List column for a specific record using the Mapper component. I tried to retrieve the record from the database, update the entity and save the changes to the record but the record is not updated in the database. It remains the same after the Update. However, the insert operation works and it mirrors the entity down to the object in the list.
User user = await _mapper.SingleAsync<T>("where Name = " + name);
user.Addresses = user.Addresses.Concat(new string[] { address });
await _mapper.UpdateAsync<T>(user);
How should this scenario be handled in Cassandra?
You can use the plus (+) and minus (-) CQL operators to append / prepend or remove items from a list.
In your case it would be:
// When using parameters, use query markers (?) instead of
// hardcoded stringified values
User user = await _mapper.SingleAsync<User>("where id = ?", id);
await _mapper.UpdateAsync<T>(
"SET connections = connections + ? WHERE id = ?", newConnections, id");
Note that append and prepend operations are not idempotent by nature. So in particular, if one of these operation timeout, then retrying the operation is not safe and it may (or may not) lead to appending/prepending the value twice.
I think in order for this to work and be efficient you may need several things:
partial update
It is atomic and doesn't require you to fetch the record first. Also, specifying only the fields you want to update avoids passing unnecessary load on the wire and relieves the pressure on the compactor.
use CqlOperator.Append/CqlOperator.Prepend/CqlOperator.SubstractAssign
Which allow you to specify only the collection items you want to add/remove.
Both of these optimizations are available via the Table API, not sure about the Mapper.
Given the following code (which is mostly irrelevant except for the last two lines), what would your method be to get the value of the identity field for the new record that was just created? Would you make a second call to the database to retrieve it based on the primary key of the object (which could be problematic if there's not one), or based on the last inserted record (which could be problematic with multithreaded apps) or is there maybe a more clever way to get the new value back at the same time you are making the insert?
Seems like there should be a way to get an Identity back based on the insert operation that was just made rather than having to query for it based on other means.
public void Insert(O obj)
{
var sqlCmd = new SqlCommand() { Connection = con.Conn };
var sqlParams = new SqlParameters(sqlCmd.Parameters, obj);
var props = obj.Properties.Where(o => !o.IsIdentity);
InsertQuery qry = new InsertQuery(this.TableAlias);
qry.FieldValuePairs = props.Select(o => new SqlValuePair(o.Alias, sqlParams.Add(o))).ToList();
sqlCmd.CommandText = qry.ToString();
sqlCmd.ExecuteNonQuery();
}
EDIT: While this question isn't a duplicate in the strictest manner, it's almost identical to this one which has some really good answers: Best way to get identity of inserted row?
It strongly depends on your database server. For example for Microsoft SQL Server you can get the value of the ##IDENTITY variable, that contains the last identity value assigned.
To prevent race conditions you must keep the insert query and the variable read inside a transaction.
Another solution could be to create a stored procedure for every type of insert you have to do and make it return the identity value and accept the insert arguments.
Otherwise, inside a transaction you can implement whatever ID assignment logic you want and be preserved from concurrency problems.
Afaik there is not finished way.
I solved by using client generated ids (guid) so that my method generated the id and returns it to the caller.
Perhaps you can analyse some SqlServer systables in order to see what has last changed. But you would get concurrency issues (What if someone else inserts a very similar record).
So I would recommend a strategy change and generate the id's on the clients
You can take a look at : this link.
I may add that to avoid the fact that multiple rows can exist, you can use "Transactions", make the Insert and the select methods in the same transaction.
Good luck.
The proper approach is to learn sql.
You can do a SQL command followed by a SELECT in one run, so you can go in and return the assigned identity.
See
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).
Hey guys, I'm having a weird time with Linq-To-SQL
I'm building a postit system that allows people to make postits and attach them to multiple objects. The database for this is a table that has the postits themselves (id, message, etc) and a linkstable which holds the records to which a postit is attached.
the weird thing I'm experiancing is the following.
When I retrieve an object from the database (using Linq-To-SQL), do some data changing and submit it again, I experience no trouble whatsoever.
Yet, when I try to make a new one I get an exception in the Submitchanges method in the datacontext: Specified Cast is not valid.
I've been looking on the web and mostly it involves some change in the mapping, but this shouldn't be the case as I can update without any problems.
T_PostIt np = new T_PostIt();
np.CreatedOn = DateTime.Now;
np.CreatedBy = Request.ServerVariables["REMOTE_USER"].ToString();
np.MarkedForDeletion = false;
np.Message = txtNewPostitMessage.Text;
np.ModifiedBy = Request.ServerVariables["REMOTE_USER"].ToString();
foreach (int i in ServerIds)
{
T_PostIt_Link pil = new T_PostIt_Link();
pil.LinkType = 'S';
pil.LinkID = i;
pil.MarkedForDeletion = false;
np.T_PostIt_Links.Add(pil);
}
dc.T_PostIts.InsertOnSubmit(np);
dc.SubmitChanges();
I use the above code and can't seem to get what I'm doing wrong.
help anyone?
Have you tried updating the properties one by one, and then save the changes back to the database? It could be that updating the entity only fails when one specific value has changed. If I may guess, it could be that the value of CreatedOn cannot be cast to a valid DateTime in the database (due to culture settings). That would explain why updating goes OK - you're not changing the value of CreatedOn here. You do, however, when inserting a new entity.
Edit: maybe this is the problem you're facing. Also, be sure to read this thread, where the topic starter eventually points to the first thread mentioning that it is an apparant bug in Linq2Sql.
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!