How can you set an entire object using LINQ to SQL? - c#

So if want to update a row in the db using the values in a received object with the same PK, how would we do that. The reason this is needed is because the objects are quite extensive and this would I create another place where we have to change field names if we update the database. So my question is how does one go about assigning an object to an object retrieved from the database using LINQ? I will show what i'm talking about to clarify.
//Foo Object Received up here, called RecFoo
using (var newContext = new FooDataContext())
{
var obj = newContext.T_Foo.Single(x=>x.Id == RecFoo.id);
//Set obj = recFoo (Directly)
newContext.SubmitChanges();
}
I know we can set each individual attribute (obj.Name = RecFoo.Name...), but is there any way that we can just take the received object using the PK id and assign it all the values that are inside of RecFoo?
EDIT: Solution
using (var newContext = new FooDataContext())
{
//var obj = newContext.T_Foo.Single(x=>x.Id == RecFoo.id);
//Set obj = recFoo (Directly)
newContext.T_Foo.Attach(recFoo);
newContext.Refresh(System.Data.Linq.RefreshMode.KeepCurrentValues, recFoo);
newContext.SubmitChanges();
}

Have you tried newContext.YourEntity.Attach(YourAlreadyPopulatedObject)
In this you just tell Linqtosql that the record already exists in the database and you are updating it.

Related

Updating Rows in IQueryable and Save Changes

I am trying to update all rows in IQueryable, that I retrieve from a database.
Is this the correct way to conduct this? When I run an Xunit test on this, the rows seem disappear.
foreach (var item in productCustomer) // productCustomer is IQueryable
{
item.isActiveStatus = (item.ExpirationYear < 2019);
}
_dbContext.SaveChanges();
Currently using EF Core 3.1
Note: Trying to refrain from creating totally new object or remapping everything; just want to update 1 member out of the 20 members.
You need to first get the objects, before they can be tracked for changes. However, if all you're doing with the IQueryable is to update a member without touching anything else, it would be faster to just execute the UPDATE query.
Consider:
using(var context = new SampleContext())
{
var commandText = "UPDATE Categories SET IsActiveStatus = ExpirationYear < 2019 --WHERE <YOUR CONDITIONS>";
//var name = new SqlParameter("#variable", "value");
context.Database.ExecuteSqlCommand(commandText/*,<params SqlParameter[]>*/);
}
change
> foreach (var item in productCustomer)
to
foreach (var item in productCustomer.ToList())
IQueryable is nothing more that a select statement on the table that triggers a database read.
No object is stored in memory until you pull it into a List or whatever datatype makes the most sense for you.

Dynamics CRM SDK : Batch update specific fields in entity

I am new to Dynamics CRM development. I want to batch update certain fields in Entity using Batch update method in Dynamics CRM Online.
I am using below code for performing batch update:
var multipleRequest = new ExecuteMultipleRequest()
{
Settings = new ExecuteMultipleSettings()
{
ContinueOnError = false,
ReturnResponses = true
},
Requests = new OrganizationRequestCollection()
};
foreach (var entity in entities.Entities)
{
UpdateRequest updateRequest = new UpdateRequest { Target = entity };
multipleRequest.Requests.Add(updateRequest);
}
ExecuteMultipleResponse multipleResponse = (ExecuteMultipleResponse)service.Execute(multipleRequest);
How can I specify only fields which I want to update instead of entire entity being updated?
Note: I have around 200,000 records to update using the above code. Currently it takes around 1.5 minute to update a single batch of 1000 records. So was thinking a way to update only required fields.
My recommended approach is to create a new Entity() object for the update. This way your update code doesn't need to worry about what fields were retrieved, it just takes the ones it cares about updating.
foreach (var entity in entities.Entities)
{
var newEntity = new Entity(entity.LogicalName, entity.Id);
//Populate whatever fields you want (this is just an example)
newEntity["new_somefield"] = entity.GetAttributeValue<string>("new_somefield").ToUpper();
UpdateRequest updateRequest = new UpdateRequest { Target = newEntity };
multipleRequest.Requests.Add(updateRequest);
}
You have to look at the way how the EntityCollection entities is filled up. If retrieving using RetrieveMultiple, then Pull the minimal fields may be the native Name field & PK Id field will come by default. This way not the whole entity will be updated back.
Avoid using AllColumns = true. Use ColumnSet to get minimal fields needed for validation.
ColumnSet = new ColumnSet("field_needed"),
Next, assign only the necessary fields like below inside loop.
foreach (var entity in entities.Entities)
{
UpdateRequest updateRequest = new UpdateRequest { Target = entity };
entity.Attributes["field_to_update"] = "field_value";
multipleRequest.Requests.Add(updateRequest);
}
My answer will help you to understand what went wrong & correcting it. Like Nicknow said, you can assign fresh entity to solve issue.

Cloning an entity in NHibernate?

I want to save a single object to the database twice. I have this code:
using (var ss = NHibHelp.OpenSession())
using (var tt = ss.BeginTransaction())
{
var entity = new Entity();
ss.Save(entity);
ss.Save(entity);
tt.Commit();
}
But this results in only one row being added to the database. How do I insert a single object into the database twice (with two different Ids) ?
You shouldn't do this - NHibernate maintains "object identity" within it's session, so it will not differentiate between ..well.. the same object. I would really advise against this, and a better solution would be to look at a way of cloning the object (either via reflection, or a Clone method), and then saving the cloned object.
If you want to ignore my advice above, you can get it to work by evicting the entity from the session, setting it's id back to it's unsaved value (depends on your mapping, but probably 0), and then saving it again.
It might also work if you just called session.Merge(entity) twice (you probably have to reset the id to it's unsaved value after the first call).
Alternatively you could use a stateless session with session.Merge() and then you don't have to evict the entity between Save's.
You can do it in two ways:
Clone the entity, should be a deep copy.
using (var ss = NHibHelp.OpenSession())
using (var tt = ss.BeginTransaction())
{
var entity = new Entity();
var clonedEntity = entity.Clone();
ss.Save(entity);
ss.Save(clonedEntity);
tt.Commit();
}
If your ID is assigned, remember to create a new ID. Deep copy have some issues with complex entities, if you have inverted collection you need to re-reference them.
2.Open a second transaction in a new session and commit it.
var entity = new Entity();
using (var ss = NHibHelp.OpenSession())
using (var tt = ss.BeginTransaction())
{
ss.Save(entity);
tt.Commit();
}
using (var ss = NHibHelp.OpenSession())
using (var tt = ss.BeginTransaction())
{
ss.Save(entity);
tt.Commit();
}

Why can't I add an object to the database? (mvc3)

It's quite a simple question: When someone click on "Edit Plan" in my ASP.NET MVC project - He doesn't edit but create a new plan with. You can see it more clearly in my answer to my qeustion here: How do I duplicate an object?
Now I want to do the same thing to its references, and I did it like that:
var featurePlans = db.FeaturePlanBaseSet.Where(f => f.PlanId == plan.Id).ToList();
db.PlanSet.AddObject(plan);
db.SaveChanges();
for (var i = 0; i < featurePlans.Count(); i++ )
{
featurePlans[i].Plan = plan;
db.FeaturePlanBaseSet.AddObject(featurePlans[i]);
}
Plan is added when I do AddObject, but Feature isn't.
I get this error:
An object with the same key already exists in the ObjectStateManager.
The existing object is in the Unchanged state.
I'll be glad to know why does it happens.
It does not appear that you save after adding FeaturePlanBaseSet. You need to call db.SaveChanges() last to save all changes.
EDIT: It also appears that you are reading an existing FeaturePlanBaseSet record from the database and then adding that record back. The next line will retrieve an existing record.
var featurePlans = db.FeaturePlanBaseSet.Where(f => f.PlanId == plan.Id).ToList();
When you add featurePlans[i], you are adding the existing record. If you plan to add a new record, Do it as follows:
for (var i = 0; i < featurePlans.Count(); i++ )
{
var featurePlan = new FeaturePlanBaseSet();
featurePlan.Plan = plan;
...set other properties
db.FeaturePlanBaseSet.AddObject(featurePlan);
}

Adding object to entityset is creating unwanted new DB row (many-to-many). Create relationship with existing object?

I am long time reader - first time poster - and after countless hours of research on this Entity Framework issue, I felt like I needed some help. I'm new to C# and new to programming, so please bear with me.
I have a fairly simple many-to-many relationship in my data model with Web 2.0 style "Tags". Shifts have tags and users have tags.
I am pulling a shift from a cache. When I try to make a copy of a shift, copying over the shift details and tags from the cached copy, I do the following (simplified).
Data.Shift s = new Data.Shift();
/* copy over a bunch of stuff from the cached shift object. I'll spare the boring details */
foreach (var t in shift.Tags) { //shift object is a cached object
Data.Tag dt = new Data.Tag
{
TagID = t.TagID,
Name = t.Name,
OrgID = t.OrgID,
};
s.Tags.Add(dt);
}
Even though I have explicitly set the TagID in the new Data.Tag object, on SaveChanges() a new tag is inserted into the DB, rather than just creating a relationship on the Tag that already exists in the DB. TagID is a PK identity column
When I try the following code:
foreach (var t in shift.Tags){
s.Tags.Add(t)
}
It obviously fails because the shift was cached from a different object context than the current requests' context.
Any thoughts? As far as I can tell:
Clearing the cache is not an option for me because of performance concerns -- I recognize that this whole issue would go away if I did this work within the same object context.
Also, pulling the Data.Tag from the DB in the current context is not an option because of perf concerns.
This seems like a really easy thing I am trying to do...
Edit
Ok -- I've tried updating my code with both solutions but I am running into trouble with both. Let's try the first one:
// ctx is grabbed up here from HttpContext.Current.Items
Data.Shift s = new Data.Shift();
/* copy over a bunch of stuff from the cached shift object. I'll spare the boring details */
foreach (var t in shift.Tags) { //shift object is a cached object
Data.Tag dt = new Data.Tag
{
TagID = t.TagID,
Name = t.Name,
OrgID = t.OrgID,
};
ObjectStateEntry entry;
ctx.ObjectStateManager.TryGetObjectStateEntry(t.EntityKey, out entry);
if (entry == null || entry.State == EntityState.Detached) {
ctx.Tags.Attach(t);
}
s.Tags.Add(dt);
}
This is throwing the following error:
An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
I am guessing that the reason I am getting is this error, is because the shift object and its tags are pulled out of a cache (obviously from different contexts). Thoughts?
It doesn't matter if you set TAgId to existing value or not. EF is stupid - it doesn't do any Upsert / Merge for you. It doesn't check if the same entity exists and if TagId is auto generated in the database it even throw away your value once you call SaveChanges.
What you have to do? You must manually tell EF that Tag is not a new entity.
Try either:
Data.Shift s = new Data.Shift();
context.Shifts.AddObject(s); // Add a new shift
foreach (var t in shift.Tags)
{ //shift object is a cached object
Data.Tag dt = new Data.Tag
{
TagID = t.TagID,
Name = t.Name,
OrgID = t.OrgID,
};
context.Tags.Attach(Tag); // Attach an existing tag
s.Tags.Add(dt);
}
context.SaveChanges();
or
Data.Shift s = new Data.Shift();
foreach (var t in shift.Tags)
{ //shift object is a cached object
Data.Tag dt = new Data.Tag
{
TagID = t.TagID,
Name = t.Name,
OrgID = t.OrgID,
};
s.Tags.Add(dt);
}
context.Shifts.AddObject(s);
// Now shift and all tags are added
// Change the state of each tag to unchanged
foreach (var tag in s.Tags)
{
context.ObjectStateManager.ChangeEntityState(tag, EntityState.Unchanged);
}
context.SaveChanges();

Categories