Get Linq to SQL to save to the database - c#

So I have the following code:
// Get the current user
_currentUser = WindowsIdentity.GetCurrent();
// Get the list of address for the current user
_dataMap = new DataMapDataContext();
_addresses = _dataMap.Addresses
.Where(address => address.InsertUserName == _currentUser.Name).ToList();
....
_addresses.Add(form.Item);
_dataMap.SubmitChanges();
When I call SubmitChanges nothing is saved in the database. Why is that? Am I missing the point? I thought with linq to sql you could just add items to your query results and then call SubmitChanges and it will work.... Clearly I am missing something.
Does it now work if you use "ToList"? If not then how do you insert stuff into the collection? (I don't think Add is part of IQueryable.)

Dont use _addresses.Add
You can't add directly to an IQueryable, you need to add it to the entity set.
Try this:
_dataMap.Addresses.InsertOnSubmit(form.Item);
_dataMap.SubmitChanges();
Of course, i can't see what form.Item is, but be aware it needs to be of the same Entity type as the _dataMap.Addresses entity set.
It makes no difference if you use .ToList().
With LINQ-SQL (unless you're using some sort of POCO mapping), you can't add items to a collection/query, you need to add the item directly into the Entity Set for the specified Data Context.
You can call .InsertOnSubmit as many times as you like, and .SubmitChanges will push all those INSERT's to the DB for you.
More info on InsertOnSubmit here.

Related

Getting weird behavior when retrieving data from Microsoft CRM using LINQ

I'm having this problem accessing the Contact entity using LINQ.
I have the 2 functions below.
If I ran the 1st function and then call the 2nd one, I seemed to be missing a lot of fields in the 2nd query. Like firstname and lastname are not showing up. They just shows up as null values. If I ran the 2nd function on its own, I am getting the right data. The only fields that shows up correctly in both runs are Id, ContactId and new_username.
If I ran the 2nd function on its own, I am getting the right data.
Any ideas what am I doing wrong?
Thanks a lot
Here are the 2 functions
public List<String> GetContactsUsernameOnly()
{
IQueryable<String> _records = from _contactSet in _flinsafeContext.ContactSet
where
_contactSet.new_FAN == "username"
orderby _contactSet.new_username
select _contactSet.new_username;
return _records.ToList();
}
public List<Contact> GetContacts()
{
IQueryable<Contact> _records = from _contactSet in _flinsafeContext.ContactSet
where
_contactSet.new_FAN == "my-username-here"
orderby _contactSet.new_username
select _contactSet;
return _records.ToList();
}
It is because you are reusing the same CRM context when you call both methods (in your case _flinsafeContext)
What the context does is cache records, so the first method is returning your contact but only bringing back the new_username field.
The second method wants to return the whole record, but when it is called after the first one the record already exists in the context so it just returns that, despite only having the one field populated. It is not clever enough to lazy load the fields that have not been populated. If this method was called first, it doesn't exist in the context so will return the whole record.
There are 2 ways to get around this:
1) Don't reuse CRMContexts. Instead create a new one in each method based on a singleton IOrganizationService.
2) There is a ClearChanges() method on your context that will mean the next time you do a query it will go back to CRM and get the fields you have selected. This will also clear any unsaved Created/Updates/Deletes etc so you have to be careful around what state the context is in.
As an aside, creating a new CRM Context isn't an intensive operation so it's not often worthwhile passing contexts around and reusing them. It is creating the underlying OrganisationService that is the slowest bit.
This behaviour can be so painful, because it is horribly inefficient and slow to return the entire record so you WANT to be selecting only the fields you want for each query.
And here's how you return just the fields you want:
IEnumerable<ptl_billpayerapportionment> bpas = context.ptl_billpayerapportionmentSet
.Where(bm => bm.ptl_bill.Id == billId)
.Select(bm => new ptl_billpayerapportionment()
{
Id = bm.Id,
ptl_contact = bm.ptl_contact
})
This will ensure a much smaller sql statement will be executed against the context as the Id and ptl_contact are the only two fields being returned. But as Ben says above, further retrievals against the same entity in the same context will return nulls for fields not included in the initial select (as per the OP's question).
For bonus points, using IEnumerable and creating a new, lightweight, entity gives you access to the usual LINQ methods, e.g. .Any(), .Sum() etc. The CRM SDK doesn't like using them against var datasets, apparently.

How to update a record without selecting that record again in ADO.NET Entity Framework?

Hi all I am doing something like this -
void update(ClasstoUpdate obj)//obj is already having values to update...
{
var data= (from i in Entityobject.ClasstoUpdate
where obj.Id==i.Id
select i).FirstorDefault();
data.Name="SomeCoolName";
EntityObject.SaveChanges();
}
I want to perform an update without again querying using the Id,is there any way I just pass the updated object to ADO.NET Entity framework and it updates it.I am sorry if I am missing something here but this is the way i have been doing it wondering if there is a simple way to update. Thanks.
The simple way to update an object is fetch it, change it, and submit changes which is what you're already doing.
Another way is to attach the object, and tell the entity framework that the object is in a modified state.
A third way is to update the object by constructing an SQL string that updates the object directly in the database without fetching it. However I wouldn't recommend doing this.
A side note: remember to check for null in your function. If you know the return value of FirstOrDefault will never be null then you should use First instead. You might also want to consider using Single instead of First.

Linq to SQL: How to get values added thru InsertOnSubmit but before SubmitChanges?

Having trouble getting this. I need get the values that I have added to a table entity through the InsertOnSubmit method. However I have not yet invoked SubmitChanges on the table.
So, I have this in a loop: mdmDC.tblMDMListItems.InsertOnSubmit(listItemsTable);
But I'd like to query mdmDC.tblMDMListItems for some values entered so far, yet I cannot seem to do that. Even after that code above the count on mdmDC.tblMDMListItems is 0.
How can I get the values added before SubmitChanges?
Thanks!!
Use DataContext.GetChangeSet and the ChangeSet.Inserts property.
// db is DataContext
ChangeSet cs = db.GetChangeSet();
foreach(var item in cs.Inserts) {
// do something
}
Note that item is not strongly-typed. In fact, it can not be because the DataContext could be tracking items of differing types corresponding to multiple tables.

Stop linq from caching tables

when a new entity in my database is created and then i request a table from the datacontext the new entity does not appear.
is linq caching the table and returning the cached version? if so how do i stop linq from doing this.
DALConnector.Dc.Order.InsertOnSubmit(NewOrder);
DALConnector.Dc.SubmitChanges();
now i click a button that shows a form with a gridview on it databound to DALConnector.Dc.Order which doesn't show the new order
How are you rebinding the grid? It does not cache the result, so I am not sure why that is an issue. You have to requery the context to get the new record... Or, if you are rebinding an object's records (like you are binding customers), you could get away with ensurihg the order is added to the Orders collection in the customer object, and not having to requery.
So if you are binding in this way:
grid.DataSource = customer.Orders;
You would only get the new order back if you did:
customer.Orders.Add(newOrder);
dc.Orders.InsertOnSubmit(newOrder);
dc.SubmitChanges();
And then, you could bind customer.Orders directly.
The Linq2Sql DataContext does not cache the complete Table, it only has a cache of the retrieved entities for change tracking purposes. If you would use a new DataContext for querying after you have inserted the order, your result will probably be the same.
AS you are using Linq2Sql, which can only be used with SQL Server, I recommend firing up the SQL Server Profiler and check if a real insert statement is submitted to the database in the first place.
Check your dbml, are you using runtime insert or a stored procedure for Order?
Also check if you're not swallowing any Exceptions the DataContext may raise on SubmitChanges().
If this does not help, please add your query code so we can verify it also.

Using Attach with Linq To Sql and Stored Procs

I am trying to use the attach method to update an entity that was retrieve via a stored proc.
The stored proc is set up to return a specific instance, which is present in my dbml. The retrieval works as expected and returns a fully populated object. The reason I need to use a stored proc is that I need to update a property on that entity at the same time that it is retrieved.
After I have retrieved this entity, I am mapping it using AutoMapper to another model which is used in another tier of the app. This tier performs a few operations, and makes a change to the entity, and passes it back to the repository for updating.
The repository converts this business model back into a database model, and attempts to attach it to the datacontext in order to take advantage of the automagic updating.
No matter what combination of Attach(entity, true) Attach(entity) etc, and it gives me messages like "Row not found or changed" or "Unable to add an entity with the same primary key".
Does anyone have any experience with the Attach method and how it can be used to update entities that did not necessarily come from the data context using query syntax (ie in this case a stored proc)?
Thanks alot
First, if you are creating a copy of the object, making changes and then trying to attach the copied object to the same DataContext as the one with the original object in it, then this would probably result in the "Unable to add an entity with the same primary key" message. One way to handle this is:
1. Get object from DataContext
2. Make changes and map object (or vice versa - whatever order)
3. Update the original object with the new values made in the other tier
4. SubmitChanges on the DataContext containing the original object
or
Get the object from a DataContext and close the DataContext
Make your changes and do your mapping
Retrieve the object from the DataContext to which you want to save
Update that object with the values from your mapped object
SubmitChanges
Alternately, when you say you are using the proc because you need to update a property at the same time that you retrieve it, I'd need to see the proc, but if you are somehow committing this update after retrieving the information, then indeed the message "row not found or changed" is correct. This would be hard to do, but you could do it if you're loading the data into a temp table, doing the update, and then using a select from the temp table to populate the object. One thing you could try is setting that property, in the L2S designer, to AutoUpdate = Never and see if that makes the problem go away. If so, this is your problem.
1: is it the same data-context, and
2: is it the same entity instance (or one that looks like it)
This would only happen for the same data-context, I suspect. If it is the same entity, then it is already there; just call SumbitChanges. Otherwise, either use a second data-context or detach the original entity.
So if I retrieved the entity via a stored proc, is it being tracked by the datacontext?
The thing is.. I'm going from the data model, to a another model that is used by another component, and then back. Its not.. really the same instance, but it does have all the same properties.
IE
public Models.Tag GetEntity()
{
var dbTag = db.PROJ_GetEntity((int)EntityStatuses.Created, (int)EntityStatuses.CreatingInApi).SingleOrDefault();
return FromDb Entity(dbEntity);
}
var appModel = GetEntity(); // gets an Entity from a stored proc (NOT GetEntity_RESULT)
appModel.MakeSomeChanges();
_Repo.Persist(appModel);
public void Persist(Models.AppModel model)
{
var dbEntity = Mapper.Map(model);
db.Attach(dbEntity);
db.SubmitChanges();
}
This is somewhat pseudo code like.. but it demostrates pretty much exactly what I am doing.
Thanks
I'm upvoting weenet's answer because he's right - you can't use Attach to apply the changes.
Unlike Entity Framework, you can only attach an L2S object to a datacontext if it has never been attached before - i.e. it's a newed entity that you want to Insert into a table.
This does cause numerous problems in multi-layered environments - however I've been able to get around many of the issues by creating a generic entity synchronisation system, which uses reflection and expression trees.
After an object has been modified, I run the dynamic delegate against a new object from the DC and the modified object, so that only the differences are tracked in the DC before generating the Update statement. Does get a bit tricky with related entities, though.

Categories

Resources