LinqtoSQL simple question on how to update a table value - c#

To all,
I'm new to LinqtoSql using C# in VS2015. The code (below) retrieves what I wish from the server table, performs the function SendSMS properly, however, I don't know how to update the DateTimeSent value in the underlying table. I look at the smsunsentline variable and intellisense says it is a local variable so I know I'm not using the linked variable I need to do the update. Any help welcome.
Greg
protected void SendQueueButton_Click(object sender, EventArgs e)
{
string smsexception;
SMSClassesDataContext dbContext = new SMSClassesDataContext();
var unsent = from SMSsent in dbContext.SMSsents where SMSsent.DateTimeSent == null select SMSsent;
foreach (SMSsent smsunsentline in unsent)
{
smsexception = "";
SendSMS(smsunsentline.To, smsunsentline.Message, ref smsexception);
smsunsentline.DateTimeSent = DateTime.Now;
dbContext.SubmitChanges();
}
}

Does your SMSSent class have one (or more) fields flagged as members of the table's primary key?
Even if the underlying table doesn't have a primary key, L2S needs to have a set of members that can be treated as a primary key for the purpose of identifying the record that is going to be updated. If no members are marked as members of the primary key, it will not be able to update records.

Your code seems okay, you should probably wrap in a using Statement
using(var context = new SMSClassesDataContext()) {
var unsentsms = context.SMSsents.Where(x => x.DateTimeSent == null);
foreach(var sms in unsentsms) {
SendSMS(sms.To, sms.Message, out string smsexception);
sms.DateTimeSent = DateTime.Now;
context.SubmitChanges();
}
}

Related

Unable to update Nullable field with Null

Facing a strange problem with EF at the moment. I have a table in database with nvarchar(MAX) data type and is a nullable field. While updating the entries in the table when I assign null to this field its not saving that null, rather keeping the old value intact. But saving the empty string in it works.
My code looks like this,
myobject.field1 = null; // assigning **null** here.
dbcontext.update();
dbcontext.saveChanges();
Any solution or guidance will be really appreciated.
What I have tried:
UseCSharpNullComparisonBehavior
and
UseDatabaseNullSemantics
EDIT:
Found the culprit, Our application has Unit of Work and Repositories implemented and we have a base Repository which includes a update method like below,
public virtual void Update(T entity)
{
//Ensure only modified fields are updated.
_dbEntities.Set<T>().Attach(entity);
var dbEntityEntry = _dbEntities.Entry<T>(entity);
foreach (var property in dbEntityEntry.OriginalValues.PropertyNames)
{
var current = dbEntityEntry.CurrentValues.GetValue<object>(property);
if (current != null)
dbEntityEntry.Property(property).IsModified = true;
}
}
In this function, updation is restricted in the null case. Though In my opinion this logic is invalid as it does not let the user change the existing value to null if user wants to.
Would love to hear the expert's opinion on this.
Sorry to bother you all.I am new to this kind of advanced logics and that make me stuck.
Try do this:
myobject.field1 = null;
dbcontext.Entry(myobject).Property(x => x.field1).IsModified = true;
dbcontext.saveChanges()

Entity Framework 6 update existing record with another record's values

I use EF database-first model in my app. It's WPF MVVM app, so i use long-living DbContext, which is created when app starts and disposed when it finishes.
There are two tables - clients and settings. settings stores all client's settings with client_id as a foreign key and settings_id as primary key.
In this settings table I have some 'default' record with settings_id=1and client_id=1. I want my app to restore 'default' settings for a client by pressing a button.
In my vewmodel i have an ObservableCollection of type Client, which is my db entity model class, and a property SelectedClient of type Client, bound to currently selected client (in some ListBox). Also i have entity class Settings, which has some fields representing different settings from a settings table. I want all these settings from 'default' record to replace currently selected client's settings.
So what am i doing:
public void OnResetClientSettingsCommandExecute()
{
var defaultSettings = Global.DbContext.Settings.FirstOrDefault(c => c.client_id == 1);
if (defaultSettings == null) return;
var tmp = defaultSettings;
tmp.client_id = SelectedClient.client_id; // doing this to change the only field which needs to remain untouched
var selectedClientSettings = Global.DbContext.Settings.FirstOrDefault(c => c.client_id == SelectedClient.client_id);
selectedClientSettings = tmp;
Global.DbContext.SaveChanges();
}
This code doesn't work at all. The only thing i get here - is changing client_id for my 'default' record in settings to SelectedClients client_id. I don't know why it happens, i thought if i would use tmp it'll be ok, but no.
I know there are some practices of using Attach() methods or changing entity's State to Modified - i tried all of them and no one worked for me, i suppose because i use long-living DbContext approach.
Honestly, i am very confused of updating records in my app in general - i just can't do it, DbContext.SaveChanges() method does not save changes to database, but rolls them back for some reason. So i have to use raw SQL-queries, which is a bit of stone age.
Please someone help me to figure out what i am doing wrong. Thanks.
You could create a class with method like this
public static void CopyValues<T>(T source, T destination)
{
var props = typeof(T).GetProperties();
foreach(var prop in props)
{
var value = prop.GetValue(source);
prop.SetValue(destination, value);
}
}
Then assign your keys to temporary variables, copy the rest of the properties and reassign your keys back to their original values.
int id = selectedClientSettings.client_id;
ObjectCopier.CopyValues<Client>(defaultSettings, selectedClientSettings);
selectedClientSettings.client_id = id;
The right way to do it. But it's exhausting !
public void OnResetClientSettingsCommandExecute()
{
var defaultSettings = Global.DbContext.Settings.FirstOrDefault(c => c.client_id == 1);
if (defaultSettings == null) return;
var selectedClientSettings = Global.DbContext.Settings.FirstOrDefault(c => c.client_id == SelectedClient.client_id);
selectedClientSettings.serviceName = defaultSettings.serviceName;
selectedClientSettings.write_delay = defaultSettings.write_delay;
// etc...
Global.DbContext.SaveChanges();
}
You should consider using AutoMapper, it could be easier to write.

EF Repository with UoW Update

I believe this is asked somewhere else but I can't find straight solution.
My Api is passing object model and on the server side every value of that object which is not passed is considered null (makes sense).
Is there way I can tell EF6 not to update entity with null values from passed object in manner I don't have to write each property and check if it's null.
Pseudo code
API
Update(int id, TaskEntity obj)
{
unitOfWork.Tasks.Update(id, userTask);
...
unitOfWork.Save()
}
Repo update
Update(int id, T entity)
{
var existingRecord = Get(id); //Gets entity from db based on passed id
if (existingRecord != null)
{
var attachedEntry = Context.Entry(existingRecord);
attachedEntry.CurrentValues.SetValues(entity);
}
}
My problem is that any data with null values will actually rewrite existing db record value with nulls.
Please point me to a solution or article where this is solved. Should I go reflections, maybe automapper could handle this (it's not its purpose i believe), or some kind of helper method should be written, as my objects can contain sub object.
Thank you in advance.
You can do something like this
Update(int id, T entity,string[] excludedFields)
{
var existingRecord = Get(id); //Gets entity from db based on passed id
if (existingRecord != null)
{
var attachedEntry = Context.Entry(existingRecord);
attachedEntry.CurrentValues.SetValues(entity);
for(var field in excludedFields)
{
attachedEntry.Property(field).IsModified = false;
}
}
}
some scenaries requires you to update part of the object and sometimes other parts, the best way in my opinion is to pass the fields to exclude from the update
hope it will help you
Personally not a big fan of hitting database and doing a get operation before doing an update. May be while doing the ajax call, you can send a list of properties which you should update (so that the scenario where updating to null values (erasing existing ones) will also be handled).
I'm doing small modifications to what #Hadi Hassan has done (without hitting database for getting the entity):
Update(T entity,string[] includedFields)
{
var existingRecord = Context.Attach(entity); // assuming primary key (id) will be there in this entity
var attachedEntry = Context.Entry(existingRecord);
for(var field in includedFields)
{
attachedEntry.Property(field).IsModified = true;
}
}
Note - attachedEntry.Property(field).IsModified will not work for related entities

Entity Framework - retrieve ID before 'SaveChanges' inside a transaction

In Entity Framework - Is there any way to retrieve a newly created ID (identity) inside a transaction before calling 'SaveChanges'?
I need the ID for a second insert, however it is always returned as 0...
ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext;
objectContext.Connection.Open();
using (var transaction = objectContext.Connection.BeginTransaction())
{
foreach (tblTest entity in saveItems)
{
this.context.Entry(entity).State = System.Data.EntityState.Added;
this.context.Set<tblTest>().Add(entity);
int testId = entity.TestID;
.... Add another item using testId
}
try
{
context.SaveChanges();
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
objectContext.Connection.Close();
throw ex;
}
}
objectContext.Connection.Close();
The ID is generated by the database after the row is inserted to the table. You can't ask the database what that value is going to be before the row is inserted.
You have two ways around this - the easiest would be to call SaveChanges. Since you are inside a transaction, you can roll back in case there's a problem after you get the ID.
The second way would be not to use the database's built in IDENTITY fields, but rather implement them yourself. This can be very useful when you have a lot of bulk insert operations, but it comes with a price - it's not trivial to implement.
EDIT: SQL Server 2012 has a built-in SEQUENCE type that can be used instead of an IDENTITY column, no need to implement it yourself.
As others have already pointed out, you have no access to the increment value generated by the database before saveChanges() was called – however, if you are only interested in the id as a means to make a connection to another entity (e.g. in the same transaction) then you can also rely on temporary ids assigned by EF Core:
Depending on the database provider being used, values may be generated client side by EF or in the database. If the value is generated by the database, then EF may assign a temporary value when you add the entity to the context. This temporary value will then be replaced by the database generated value during SaveChanges().
Here is an example to demonstrate how this works. Say MyEntity is referenced by MyOtherEntity via property MyEntityId which needs to be assigned before saveChanges is called.
var x = new MyEntity(); // x.Id = 0
dbContext.Add(x); // x.Id = -2147482624 <-- EF Core generated id
var y = new MyOtherEntity(); // y.Id = 0
dbContext.Add(y); // y.Id = -2147482623 <-- EF Core generated id
y.MyEntityId = x.Id; // y.MyEntityId = -2147482624
dbContext.SaveChangesAsync();
Debug.WriteLine(x.Id); // 1261 <- EF Core replaced temp id with "real" id
Debug.WriteLine(y.MyEntityId); // 1261 <- reference also adjusted by EF Core
The above also works when assigning references via navigational properties, i.e. y.MyEntity = x instead of y.MyEntityId = x.Id
If your tblTest entity is connected to other entities that you want to attach, you don't need to have the Id to create the relation. Lets say tblTest is attached to anotherTest object, it the way that in anotherTest object you have tblTest object and tblTestId properties, in that case you can have this code:
using (var transaction = objectContext.Connection.BeginTransaction())
{
foreach (tblTest entity in saveItems)
{
this.context.Entry(entity).State = System.Data.EntityState.Added;
this.context.Set<tblTest>().Add(entity);
anotherTest.tblTest = entity;
....
}
}
After submitting the relation would be created and you don't need to be worry about Ids and etc.
You can retreive an ID before calling .SaveChanges() by using the Hi/Lo alhorithm. The id will be assigned to the object once it is added to dbcontext.
Example configuration with fluent api:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Entity>(e =>
{
e.Property(x => x.Id).UseHiLo();
});
}
An excerpt from the relevant Microsoft article:
The Hi/Lo algorithm is useful when you need unique keys before committing changes. As a summary, the Hi-Lo algorithm assigns unique identifiers to table rows while not depending on storing the row in the database immediately. This lets you start using the identifiers right away, as happens with regular sequential database IDs.
#zmbq is right, you can only get the id after calling save changes.
My suggestion is that you should NOT rely on the generated ID's of the database.
The database should only a detail of your application, not an integral and unchangeable part.
If you can't get around that issue use a GUID as an identifier due it's uniqueness.
MSSQL supports GUID as a native column type and it's fast (though not faster than INT.).
Cheers
A simple work around for this would be
var ParentRecord = new ParentTable () {
SomeProperty = "Some Value",
AnotherProperty = "Another Property Value"
};
ParentRecord.ChildTable.Add(new ChildTable () {
ChildTableProperty = "Some Value",
ChildTableAnotherProperty = "Some Another Value"
});
db.ParentTable.Add(ParentRecord);
db.SaveChanges();
Where ParentTable and ChildTable are two tables connected with Foregin key.
You can look up the value in the ChangeTracker like this:
var newEntity = new MyEntity();
var newEntity.Property = 123;
context.Add(newEntity);
//specify a logic to identity the right entity here:
var entity = context.ChangeTracker.Entries()
.FirstOrDefault(e => e.Entity is MyEntity myEntity &&
myEntity.Property == newEntity.Property);
//In this case we look up the value for an autogenerated id of type int/long
//it will be a negative value like -21445363467
var value = entity.Properties?
.FirstOrDefault(pe => pe.Metadata.GetColumnName() == nameof(MyEntity.Id))?.CurrentValue;
//if you set it on another entity, it will be replaced on SaveChanges()
My setup was mysql 5.7, but should work in other environments also.

How to write Linq method in data tier?

I am thinking about how to use Linq in the classic 3-tier archetecture of .net project. Apprently, Linq to SQL should appear in Data tier. The reason I choose Linq is because it will save me much time on code than using store procedure. I did some search on line about the insert/update/delete method of Linq, but didn't find an appropriate method for record update using entities. Usually, people will do update using this way:
public void UpdateUser(String username, String password, int userId)
{
using (var db = new UserDataContext()){
var user = db.user.Single(p => p.Id = userId);
user.Username = username;
user.Password = password;
db.SubmitChanges();
}
}
Why we don't use entity to pass the record like this:
public void Update(Application info)
{
VettingDataContext dc = new VettingDataContext(_connString);
var query = (from a in dc.Applications
where a.Id==info.Id
select a).First();
query = info;
try{
dc.SubmitChanges();
}
catch(Exception e){
//...
}
}
But unfortunately, the above code is wrong because of "query=info", but if I assign each value from "info" to "query", it works fine. like
query.firstName=info.firstName;
query.lastName=info.lastName;
So if this table have 40 fields, I have to write 40 lines code. Is there any easier way to do the update? Hope I describe this issue clearly.
Adding another answer as a comment was not sufficient to expand on my previous answer.
Lets take a step back and look at what you want to do here from a logical perspective. You want to tell your data access layer how it should update the database, with all the new/changed values it needs to write.
One very common way of doing this is to pass an entity which has those changes (which is what you're doing in your example). This can become tricky, as you have seen, because if you simply overwrite the entity variable with the changed entity, Linq2Sql will lose change tracking... just because the new entity is assigned to the same variable, doesn't mean that Linq2Sql automatically picks up changes from the new object... in fact Linq2Sql has no knowledge of the new object at all...
Example:
// In domain layer:
MyEntity entity = new MyEntity();
entity.PrimaryKey = 10;
entity.Name = "Toby Larone";
entity.Age = 27;
myDataRepository.Update(entity);
// In data layer:
void Update(MyEntity changedEntity)
{
using (var db = new DataContext())
{
var entity = (from e in db.MyEntities
where e.PrimaryKey == changedEntity.PrimaryKey
select e).First();
// Linq2Sql now has change tracking of "entity"... any changes made will be persisted when SubmitChanges is called...
entity = changedEntity;
// Linq2Sql does **not** have change tracking of changedEntity - the fact that it has been assigned to the same variable that once stored a tracked entity does not mean that Linq2Sql will magically pick up the changes...
db.SubmitChanges(); // Nothing happens - as far as Linq2Sql is concerned, the entity that was selected in the first query has not been changed (only the variable in this scope has been changed to reference a different entity).
}
}
Now you've already seen that assigning each field to the entity rather than replacing it works as intended - this is because the changes are being made to the original entity, which is still inside the Linq2Sql change tracking system..
One possible solution to this problem would be to write a method that "applies" the changes of another Entity to an existing one, ie:
partial class MyEntity
{
void ApplyChanges(MyEntity changedEntity)
{
this.PrimaryKey = changeEntity.PrimaryKey;
this.Name = changedEntity.Name;
this.Age = changedEntity.Age;
}
}
and then your data access would look like this:
// In data layer:
void Update(MyEntity changedEntity)
{
using (var db = new DataContext())
{
var entity = (from e in db.MyEntities
where e.PrimaryKey == changedEntity.PrimaryKey
select e).First();
// Linq2Sql now has change tracking of "entity"... any changes made will be persisted when SubmitChanges is called...
entity.ApplyChanges(changedEntity);
db.SubmitChanges(); // Works OK...
}
}
But im sure you don't like this solution - because all you have done is effectively move the repetitive field assignment out of the repository and into the Entity class itself...
Going back to the logical perspective - all you really need to do is tell the data access repository 2 things - 1) which record you want to update and 2) what the changes are. Sending an entirely new entity which encapsulates those two requirements is not necessary to achieve that goal, in fact I think it's very inefficient.
In the following example, you are sending the data repository only the changes, not an entire entity. Becuase there is no entity, there are no change tracking issues to work around
Example:
// In domain layer:
myDataRepository.Update(10, entity =>
{
entity.Name = "Toby Larone";
entity.Age = 27;
});
// In data layer:
void Update(int primaryKey, Action<MyEntity> callback)
{
using (var db = new DataContext())
{
var entity = (from e in db.MyEntities
where e.PrimaryKey == primaryKey
select e).First();
// Linq2Sql now has change tracking of "entity"... any changes made will be persisted when SubmitChanges is called...
// The changes that were sent are being applied directly to the Linq2Sql entity, which is already under change tracking...
callback(entity);
db.SubmitChanges();
}
}
In the previous examples, the field assignments were happening twice - once when you described the changes you wanted to make, and again in the data repository when you needed to apply those changes to a Linq2Sql change tracked entity.
Using the callback, the field assignments only happen once - the description of the change itself is what updates the tracked entity.
I hope I explained this well enough :)
Think about what the data repository actually requires in order to perform the update. It does not require an object that contains those changes, but a description of what changes need to be made. This can be encapsulated easily into a callback delegate...
public void UpdateUser(int userId, Action<User> callback)
{
using (var db = new DataContext())
{
User entity = db.Users.Where(u => u.Id == userId).Single();
callback(entity);
db.SubmitChanges();
}
}
myrepository.UpdateUser(userId, user =>
{
user.Username = username;
user.Password = password;
// etc...
});
query is not the same type as info. They may have the same properties to you, but the code doesn't know that.
Now, if you want to avoid writing a bunch of unnecesary code, you can use a third party library like AutoMapper which can do that for you.

Categories