InsertAllOnSubmit only inserts one item - c#

I am trying to use InsertAllOnSubmit to do multiple inserts, but only 1 item ever gets inserted into the table. The only reason I can think that this is happening is something to do with the generation of the Primary Key field, I am currently allowing the code to auto generate this field, and it doesn't seem to be doing that. Can anybody help?
List<rewardsClaimed> lstRewardsClaimed = new List<rewardsClaimed>();
for (int i = 0; i < ticket.delivery.quantity; i++)
{
rewardsClaimed claim = result;
lstRewardsClaimed.Add(claim);
}
dc.rewardsClaimeds.InsertAllOnSubmit(lstRewardsClaimed);
dc.SubmitChanges();
EDIT :
I have found out what the problem is....the ID field gets set to 0 by default, so that when the insert is done, since all rows have the same ID, they are treated as 1 row. How would I prevent this?

The problem is that List and Table behave completely different.
A List<T> allows you to add the same instance more than once without checking the reference in other words in your list you have multiple references to the same object.
Table<T> in the other hand when you call InsertAllOnsubmit method checks every item in the collection to see if its already "marked" to be inserted in the table. If the object its already "marked" skips it.
What is happening with your code is that you are passing the List of claims that make reference n number of times to the same object. When is passed to Table<T> the first ocurrence is marked for insertion. Since the other items in the list are the same object, they are already marked for insertion.
Hope this clarifies.

Everyone is asking to create new instance of the class RewardsClaimed. But I thought that it is not the correct reason. Hence I tried the following sample code and found that 5 different instances are added in the list.
Part 1: Showing that same item can be added to local list without creating new instance (Its not the answer)
Code:
Results:
Part 2: Creation of new primary key will be the solution. (This is the issue and solution.)
I would suggest that, please check the data in your PrimaryID Column is not repeated. By this I mean, if your primary key is not automatically generated and you generate it manually, chances are it gets rows with same primarykeys n number of times. If it is repeated then it will only insert single instance of it.
Edit: How to auto generate Field Value
If you want to auto-generate primary key refer this.

you are not creating new instance of claim.
rewardsClaimed claim = new rewardsClaimed();

List<rewardsClaimed> lstRewardsClaimed = new List<rewardsClaimed>();
for (int i = 0; i < ticket.delivery.quantity; i++)
{
rewardsClaimed claim = new rewardsClaimed();
claim.property = result.property; // do this foreach property except id field
lstRewardsClaimed.Add(claim);
}
dc.rewardsClaimeds.InsertAllOnSubmit(lstRewardsClaimed);
dc.SubmitChanges();

Related

Get updated row in ASPxGridView.RowUpdating event with composite KeyFieldName

I'm trying to create a custom edit script for my ASPxGridView. I have a second grid in which I used the code below to obtain the row that has been updated. This, however, doesn't work because my grid has a composite KeyFieldName (because the table it's based on has a primary key made up of two columns). This results in the FindVisibleIndexByKeyValue method always returning -1.
Any ideas on how I could obtain the row some other way?
object key = e.Keys[grid.KeyFieldName];
int row = grid.FindVisibleIndexByKeyValue(key);
Edit: The problem actually is that e.Keys[grid.KeyFieldName] returns null.
This can be accomplished by saving the keys into an array of objects one by one and passing that array to FindVisibleIndexByKeyValue().
object[] key = new object[2];
key[0]= e.Keys["firstKey"];
key[1] = e.Keys["secondKey"];
int row = grid.FindVisibleIndexByKeyValue(key);

Entity Framework ensure objects get inserted in order

I have a table Rules on my database. I insert rules like:
Rule[] rulesToInsert = // some array of rules to insert
using(var db = new MyEntities())
{
foreach(var rule in rulesToInsert)
db.Rules.Add(rule);
db.SaveChanges();
}
When I retrieve later the rules that I have just added I notice they are in a different order. What is the best way to retrieve them in the order I added them? Should I call db.SaveChanges() every time I add a new rule? Or should I add a new column called SortOrder? Why are the items not being added in the order I added them?
Edit
The id is a guid (string) because one rule can have other rules. In other words I am creating a tree structure. (The rules table has a foreign key to itself). It was crashing when I used the primary key as an integer and it autoincremented so I just used a guid instead. I guess I will add a separate column called sort order.
Tables have no sort order (new rows are not guaranteed to be added to the end or any other place). The only safe way to retrieve rows in any particular order is to have a query with Order by.
So yes you will need to add a SortOrder column. (Can just set it as an identity column.)
If you want your items to be inserted in the order you add them in the foreach statement, you have to make a big compromise, to call the db.SaveChanges in each iteration.
foreach(var rule in rulesToInsert)
{
db.Rules.Add(rule);
db.SaveChanges();
}
I say that's a big compromise, because for each rule you have to insert you have to make a round-trip to the database, instead of doing only one round-trip as in your original code.
One possible workaround, it would be to add an extra column in the corresponding table in your database, that would hold the information of order. If you do so, you could add one more property in the rule object and refactor a bit your code. Then you will have the expected result.

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!

How do you add a field to an rfcTable using SAP Nco 3.0?

I can't understand the documentation and really need a concrete example.
I've already created the destination. Here I define my BAPI:
IRfcFunction BapiIncomingInvoiceGetDetail = SapRfcRepository.CreateFunction("BAPI_INCOMINGINVOICE_GETDETAIL");
Set my imports, invoke it, and then get my exports - one of which is a table:
IRfcTable ITEMDATATable = BapiIncomingInvoiceGetDetail.GetTable("ITEMDATA");
I now want to add a field to each item in the table ITEMDATATable and set its' value so I can reference it later as if it were one of thefields returned by the BAPI. Can anyone tell me how?
EDIT: Okay, I've made some progress:
RfcFieldMetadata newField = new RfcFieldMetadata("SKU_AMT",0,0,0);
ITEMDATATable.CurrentRow.Metadata.AddField(newField);
ITEMDATATable.SetValue("SKU_AMT",myItemData.SKU_AMT);
However, when I try to set the value, I get RfcInvalidStateException "Cannot add an element to locked STRUCTURE BAPI_INCINV_DETAIL_ITEM".
Any way around this?
you can't append columns to the table, the fields are already defined. You need to add a row to the table and populate the fields of that row. This should work (although i can't test it right now):
IRfcTable ITEMDATATable = BapiIncomingInvoiceGetDetail.GetTable("ITEMDATA");
ITEMDATATable.Append();
ITEMDATATable.SetValue("SKU_ATM",myItemData.SKU_AMT);

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