I do my query...
var result = from u in tdc.tblUsers
where u.UserID == userID
select u;
and then I change the values I want to:
foreach (tblUsers u in result)
{
//change values (and no im not changing the primary key or foreign keys)
}
then I submit changes
tdc.SubmitChanges();
When it hits submit changes, it throws exception that the row wasn't found or was changed. I am the only person using this so there's no other conflicts with accessing the db or locking. Why would it throw the ChangeConflictException? I have stepped through with debugger and the data persists all the way through the process, including the changes that I'm trying to make.
I have also tried it this way before and got the same error
tblUsers result = (from u in tdc.tblUsers
where u.UserID == userID
select u).Single();
result.Address = address;
result.Phone = phone;
tdc.SubmitChanges();
It will only ever retrieve 1 record with this query since UserID is the primary key.
I've done this many times and it has worked. Every example I've found is exactly what I have.
Maybe you work with different context? Try to encapsulate it by using
using (myContext ctx = new myContext())
{
var user = ctx.users.first();
user.name="blah";
ctx.SubmitChanges();
}
Quite often, if you look at the actual SQL that Linq-to-SQL generates, you'll see that it is being really over-zealous with matching the database row that you initially retrieved. Imagine that you have a table with columns ID(PK), A, B, C. You would think that if you updated column C for a row, it should be sufficient to update the row with a matching primary key. But what often happens is that Linq-to-SQL is also trying to match on columns A and B as well. Normally, that's fine. Unless you have concurrent writes, either from multi-threading or multi-processes, and something else modifies column A or B for the record that you are trying to update. Then you get these System.Data.Linq.ChangeConflictException: Row not found or changed. errors when you call SubmitChanges() on your data context.
Related
I have a Linq2SQL query running against a database provided by a third party. The main part of the query looks like this:
var valuationQuery =
from v in context.Valuations
where v.ModelId == QualifiedModelId.ModelId
&& v.QualifyModelId == QualifiedModelId.Qualifier
&& v.LanguageCode == QualifiedModelId.LanguageCode
&& v.Edition == Data.Meta.Edition.CurrentEdition.Date
&& v.RegDate == yearReg.RegistrationDate
&& v.ValTypeDescription == "Normal"
&& v.MileageBandID == MileageBand
When I loop around it with a foreach loop, it works or fails depending on the select at the end. When the select specifies all the fields like this...
select new
{
v.Value1,
v.Value2,
v.Value3,
... snip ...
v.Value14,
v.Value15,
v.ValueTypeID
};
... it works normally. When I do the following, the loop iterates the correct amount of times, but brings back the first record every time:
select v;
I want to be able to select all the fields without specifying the names in case the vendor adds more fields (they really are called "Value1" upto "Value15"), which means I can change one constant in my code and update the DBML and all the relevant code will lookup from the correct amount of fields. This query (and similar ones) are used in various places, so I'm looking for the least-effort in the future!
I have run SQL Profiler to ensure the query being run returns the correct results, and it does.
The foreach loop is this (the Convert's are due to the very badly designed database having very inconsistent datatypes):
foreach (var record in valuationQuery)
{
int CurrentValType = Convert.ToInt32(record.ValueTypeID);
string FieldName = "Value";
if (MPLower.MileagePointID >= 1 && MPLower.MileagePointID <= MaxMileagePoints)
{
FieldName = "Value" + MPLower.MileagePointID.ToString().Trim();
MPLower.MileagePointPounds[CurrentValType] = Convert.ToInt32(record.GetType().GetProperty(FieldName).GetValue(record, null));
}
if (MPHigher.MileagePointID >= 1 && MPHigher.MileagePointID <= MaxMileagePoints)
{
FieldName = "Value" + MPHigher.MileagePointID.ToString().Trim();
MPHigher.MileagePointPounds[CurrentValType] = Convert.ToInt32(record.GetType().GetProperty(FieldName).GetValue(record, null));
}
}
I'm new to C# (I've inherited some code), so I realise it's probably something stupid I've done or not done!! Please can anyone help?
Identity Maps
A common problem when using ORMs (ok, maybe not exactly common, but it can happen) is that a query which you expect to return distinct records ends up returning multiple copies of the same record. This is often caused by the ORM's Identity Map. Here's a quick overview of how it normally works.
The identity map is essentially an object cache, based on the primary key of each object.
When you ask the ORM for a record with a certain primary key, it'll check to see if the record already exists in the identity map. If it does already exist, it'll return the existing record.
This is usually pretty handy, but sometimes things go wrong. If two objects have the same primary key, or if you haven't specified what the primary keys are (forcing the ORM to guess), the identity map can't distinguish between them, and the first one will always be returned.
The moral of the story is, always double-check your primary keys if you are seeing multiple copies of the same record where you shouldn't be!
In this question, the code
select new
{
v.Value1,
v.Value2,
v.Value3,
... snip ...
v.Value14,
v.Value15,
v.ValueTypeID
};
works because you are using the select new{} projection to return an anonymous type, which bypasses the identity map.
select v
selects the objects directly, which does use the identity map, causing the problem you were seeing.
Application presented with "Sequence Contains More Than One Entity" error. Knowing this is usually the result of a .SingleOrDefault() command in Linq, I started investigating. I can verify that the production server has many instances of duplicate keywords, so that's where I begin.
I have the following Keyword table:
id INT (NOT NULL, PRIMARY KEY)
text NVARCHAR(512)
active INT
active is just a way to "enable/disable" data if the need strikes me. I'm using LINQ to SQL and have the following method implemented:
public Keyword GetKeyword(String keywordText)
{
return db.Keywords.SingleOrDefault(k => (k.text.ToUpper() == keywordText.ToUpper()));
}
The idea is that I attach keywords through an association table so that multiple objects can reference the same keyword. There should be no duplicate text entries within the Keyword table. This is not enforced on the database, but rather through code. This might not be best practice, but that is the least of my problems at the moment. So when I create my object, I do this:
Keyword keyword = GetKeyword(keywordText)
if(keyword == null)
{
keyword = new Keyword();
keyword.text = keywordText;
keyword.active = Globals.ACTIVE;
db.Keywords.InsertOnSubmit(keyword);
}
KeywordReference reference = new KeywordReference();
reference.keywordId = keyword.id;
myObject.KeywordReferences.Add(reference);
db.SubmitChanges();
this code is actually paraphrased, I use a repository pattern, so all relevant code would be much longer. However, I can assure you the code is working as intended, as I've extensively tested it. The problem seems to be happening on the database level.
So I run a few tests and manual queries on my test database and find that the keyword I passed in my tests is not in the database, yet if I do a JOIN, I see that it is. So I dig a little deeper and opt to manually scan through the whole list:
SELECT * FROM Keyword
return 737 results. I decided I didn't want to look through them all, so I ORDER BY text and get 737 results. I look for the word I recently added, and it does not show up in the list.
Confused, I do a lookup for all keywordIds associated with the object I recently worked on and see a few with ids over 1,000 (the id is set to autoincrement by 1). Knowing that I never actually delete a keyword (hence the "Active" column) so all ids from 1 to at least those numbers over 1,000 should all be present, I do another query:
SELECT * FROM Keyword ORDER BY id
returns 737 results, max ID stops at 737. So I try:
SELECT * FROM Keyword ORDER BY id DESC
returns 1308 rows
I've seen disparities like this before if there is no primary key or no unique identifier, but I have confirmed that the id column is, in fact, both. I'm not really sure where to go from here, and I now have the additional problem of about 4,000+ keywords on production that are duplicate, and several more objects that reference different instances of each.
If you somehow can get all your data then your table is fine, but index is corrupted.
Try to rebuild index on your table:
ALTER INDEX ALL ON Your.Table
REBUILD WITH (FILLFACTOR = 80, SORT_IN_TEMPDB = ON, STATISTICS_NORECOMPUTE = ON);
In rare situations you can see such errors if your hard drive fails to write data due to power loss. Chkdsk should help
I use the following code :
List<vw_GetIMeasurements> Imeasurements = context.vw_GetIMeasurements.Where(f => f.MEMBERID == userID).Distinct().ToList();
This returns a list with 12 Values like it should but these values are always the same(even though they aren't in the DB.(Even if they were distinct should solve this)
DB :
The raw value that is returned is also wrong.
What would be the cause of this issue and how can I resolve it?
I have had this problem before - it turned out that the view did not have unique entity keys set - make sure your primary keys for your view that is auto created by entity framework is indeed unique...
I had a similar issue - the database view looked fine in SQL server but when debugging, duplicate rows were appearing where rows shared a particular attribute value.
I found that one of the important unique keys was from a outer join table - therefore had the potential to be null - and the model was not assigning as unique.
I was able to fix this problem by setting this field to ISNULL(field, '') - ensuring that a value is always returned - and upon updating, the model correctly interprets the field as unique and as part of a compound key and the rows returned correctly.
I know that one might argue the view design is at fault (i.e. I should not be using an outer join), but in this instance, there was a specific need for the outer join. The fix works because the compound key is still unique even if "" is returned multiple times.
Maybe try a more simple syntax like this
var measure = from f in context.vw_GetIMeasurements
where f.MEMBERID == userID
select f;
This kind of thing is working for me..
The issue is infact what Richard described. However I was unable to choose a correct "Unique Key" so this caused more issue.
I solved my problem by creating a custom made class and creating this in SQL. I also limited my Select to 2 of the 3 Columns.
List<Measurement> result = (from f in context.vw_GetIMeasurements where f.MEMBERID == userID select new Measurement { Category = f.atcmCATEGORYCODEID, Size = f.imMeasurementNumber }).ToList();
Measurement is in the case the self made Class.
I've searched and searched stackoverflow and www, but have found no answers to this question.
I am looping through a number of records and under certain conditions I'm inserting new records into table A. Then I'm looping again on another data source (which cannot be merged with the first one), and if that be the case, I want to insert new records into the same table A. I only want to commit the records at the end of the process, but it'll give a primary key violation error if I just insert them.
Note: linq is not managing primary keys. Probably because I'm sort of a noob with linq and don't really know how to get linq to work with Oracle sequences.
My question is how do I check the existing context for the records I have inserted. This is what I am doing.
foreach(var rec in recordList1)
{
...
dataContext.InsertOnSubmit(obj);
}
foreach(var rec in recordList2)
{
if ( ! [check context here for existing record] )
{
...
dataContext.InsertOnSubmit(obj);
}
}
dataContext.SubmitChanges();
I've tried querying the context in different ways, but it'll only return committed values.
Thanks in advance!
Best regards.
To access the objects inserted, updated, deleted in the datacontext you need to call GetChangeSet.
var changed = dataContext.GetChangeSet();
var inserted = changed.Inserts;
var updated = changed.Updates;
var deleted = changed.Deletes;
I have a many to many relationship between 2 entities.
UserInfo and Campaign and the third table UserInfoCampaigns
On the front end a user should be able to update the user campaigns by using multiple checkboxes.
So I have:
var selectedCampaignsIds = new int[] {1,2,3}
var user = _extendedUserService.GetUser(new Guid(userId));
var newCampaigns =_campaignrepository.GetAllCampaignsByIds(selectedCampaignsIds);
I can assign newly selected campaigns by following:
foreach (var campaign in newCampaigns)
{
var userInfoCampaign = new UserInfoCampaign { UserInfoId = user.Id, CampaignId = campaign.Id };
_campaignrepository.SaveUserInfoCampaign(userInfoCampaign);
}
My question is how do I update UserInfo campaigns taking into consideration that a user might have or might not have existing campaigns?
Do I delete all existing UserInfoCampaigns and then reassign with new ones? Or there is a more optimal way of updating the UserInfo campaigns without deleting them first using LINQ to SQL?
Thanks a lot.
Generally, you'd delete them and recreate them. That's the way I handle this kind of situation of many to many.
If you went for (Delete all) solution then you may consider that the ids will increase in your table in none continues form (I'm assuming that your PK is an int), if you dont care about that then delete them then re-add
if you want the identity to be in a continues form you may set a flag (IsDeleted) in your campaigns table that refers to the campaign as deleted, you set it to ture when user delete a campaign and set it false when user re-select it from the UI this insure less more records but take a more bit work in your code
Generally, we just let SQL handle it. You can specify ON DELETE on the relationships in SQL, you can CASCADE or SET DEFAULT or SET NULL depending on what behaviour you want.
Here's an example for ON DELETE CASCADE:
http://www.codeproject.com/KB/cs/CascadingDeletes_cs.aspx