Entity Framework Core GetOrAdd Method - asp.net-core

I'm working on a post method that should have a really good performance.
I have a value in the request body that will look in the database for the row that is connected with that value and return it and add it as a foreign key.
So how it is now:
Look in the database and check if the data already exists
If no add it to the database
Look that added or already existing data in the database and join it to the entity
So now there are 3 calls to the database
I was wondering if there is some kind of GetOrAdd method that will connect the table to my data if it exists and if it not exists add it to the database so it will most of the time only have 1 call to the database instead of always 3 calls

Please read the following doc
Here is an "Insert or Update" pattern:
public void InsertOrUpdate(Blog blog)
{
using (var context = new BloggingContext())
{
context.Entry(blog).State = blog.BlogId == 0 ?
EntityState.Added :
EntityState.Modified;
context.SaveChanges();
}
}
Of note, once you hit SaveChanges() you can expect your in memory object (blog, in this case) to be the same object that is stored in the database, and would not have to make a 3rd call to retrieve it again. EF Core will update the Primary Key with the actual persisted Id.

using (var context = new BloggingContext())
{
var blog = new Blog {Id = 1, Url = "blablabla" };
context.Blogs.Update(blog);
await context.SaveChangesAsync();
}
If a reachable entity has its primary key value set then it will be tracked in the Microsoft.EntityFrameworkCore.EntityState.Modified state. If the primary key value is not set then it will be tracked in the Microsoft.EntityFrameworkCore.EntityState.Add state.
This comment is from Entity Framework Core's Update method. You just need to call Update method if entity is exist in Database it will be updated otherwise will be created as new record.

Related

Update command in Fluent NHibernate

I am trying to update an object after retrieving it from a database.
This fires 2 queries , one for the select and the other for the update, is there any way of update an object using Fluent NHiberNate firing only one query ?
My code is as below:
var userProfile = userProfileRepository
.Find(x => x.ClientId == clientId)
.FirstOrDefault();
/* update UserProfile object here */
userProfileRepository.SaveOrUpdate(userProfile);
the SaveOrUpdate Method looks as such :
public bool SaveOrUpdate(T instance)
{
using (var session = SessionManager.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
session.SaveOrUpdate(instance);
transaction.Commit();
}
return true;
}
}
In case that your issue is:
regardless of what I do, SaveOrUpdate() always sends SELECT then UPDATE
You should check the doc:
5.1.4.7. Assigned Identifiers
If you want the application to assign identifiers (as opposed to having NHibernate generate them), you may use the assigned generator. This special generator will use the identifier value already assigned to the object's identifier property. Be very careful when using this feature to assign keys with business meaning (almost always a terrible design decision).
Due to its inherent nature, entities that use this generator cannot be saved via the ISession's SaveOrUpdate() method. Instead you have to explicitly specify to NHibernate if the object should be saved or updated by calling either the Save() or Update() method of the ISession.
So, if your Fluent configuration sets the ID to be assigned - NHibernate has no other way then check if it
exists
or is new
because used method was SaveOrUpdate()
Solution(s)
1) Change the ID to be generated by DB or NHiberante 2) use explicit Update()
Are you trying to create an
UPDATE ... WHERE ...
statement?
AFAIK the NHibernate way to do this, is to select the appropriate objects (using the WHERE clause), update the fields, and persist them again.
var tempObjects = _session.Query<myObject>.Where(o => o.Id > 500);
// update proxy objects
foreach (var o in tempObjects)
{
o.MyValue = updatedValue;
}
// commit updated objects
_session.Update(tempObjects);
To be honest, we've used ISession.CreateSQLQuery ourselves. I hate using SQL in code because it breaks in refactoring, but if you must - here's how:
_session.CreateSQLQuery(
#"UPDATE [MyTable] SET [MyValue]=:updatedvalue WHERE Id > 500")
.SetParameter("updatedvalue", updatedValue)
.ExecuteUpdate();

"Convert" Entity Framework program to raw SQL

I used Entity Framework to create a prototype for a project and now that it's working I want to make the program ready for production.
I face many challenges with EF, the biggest one being the concurrency management (it's a financial software).
Given that it seems to have no way to handle pessimistic concurrency with EF, I have to switch to stored procs in SQL.
To be honest I'm a bit afraid of the workload that may represent.
I would like to know if anybody have been in the same situation before and what is the best strategy to convert a .net code using EF to raw SQL.
Edit:
I'm investigating CLR but it's not clear if pessimistic concurency can be manage with it. is it an option more interesting than TSQl in this case ? It would allow me to reuse part of my C# code and structure of function calling another functions, if I understand well.
I was there and the good news is you don't have to give up Entity Framework if you don't want to. The bad news is you have to update the database yourself. Which isn't as hard as it seems. I'm currently using EF 5 but plan to go to EF 6. I don't see why this still wouldn't work for EF 6.
First thing is in the constructor of the DbContext cast it to IObjectContextAdapter and get access to the ObjectContext. I make a property for this
public virtual ObjectContext ObjContext
{
get
{
return ((IObjectContextAdapter)this).ObjectContext;
}
}
Once you have that subscribe to the SavingChanges event - this isn't our exact code some things are copied out of other methods and redone. This just gives you an idea of what you need to do.
ObjContext.SavingChanges += SaveData;
private void SaveData(object sender, EventArgs e)
{
var context = sender as ObjectContext;
if (context != null)
{
context.DetectChanges();
var tsql = new StringBuilder();
var dbParams = new List<KeyValuePair<string, object>>();
var deletedEntites = context.ObjectStateManager.GetObjectStateEntries(EntityState.Deleted);
foreach (var delete in deletedEntites)
{
// Set state to unchanged - so entity framework will ignore
delete.ChangeState(EntityState.Unchanged);
// Method to generate tsql for deleting entities
DeleteData(delete, tsql, dbParams);
}
var addedEntites = context.ObjectStateManager.GetObjectStateEntries(EntityState.Added);
foreach (var add in addedEntites)
{
// Set state to unchanged - so entity framework will ignore
add.ChangeState(EntityState.Unchanged);
// Method to generate tsql for added entities
AddData(add, tsql, dbParams);
}
var editedEntites = context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified);
foreach (var edit in editedEntites)
{
// Method to generate tsql for updating entities
UpdateEditData(edit, tsql, dbParams);
// Set state to unchanged - so entity framework will ignore
edit.ChangeState(EntityState.Unchanged);
}
if (!tsql.ToString().IsEmpty())
{
var dbcommand = Database.Connection.CreateCommand();
dbcommand.CommandText = tsql.ToString();
foreach (var dbParameter in dbParams)
{
var dbparam = dbcommand.CreateParameter();
dbparam.ParameterName = dbParameter.Key;
dbparam.Value = dbParameter.Value;
dbcommand.Parameters.Add(dbparam);
}
var results = dbcommand.ExecuteNonQuery();
}
}
}
Why we set the entity to unmodified after the update because you can do
var changed properties = edit.GetModifiedProperties();
to get a list of all the changed properties. Since all the entities are now marked as unchanged EF will not send any updates to SQL.
You will also need to mess with the metadata to go from entity to table and property to fields. This isn't that hard to do but messing the metadata does take some time to learn. Something I still struggle with sometimes. I refactored all that out into an IMetaDataHelper interface where I pass it in the entity type and property name to get the table and field back - along with caching the result so I don't have to query metadata all the time.
At the end the tsql is a batch that has all the T-SQL how we want it with the locking hints and containing the transaction level. We also change numeric fields from just being set to nfield = 10 but to be nfield = nfield + 2 in the TSQL if the user updated them by 2 to avoid the concurrency issue as well.
What you wont get to is having SQL locked once someone starts to edit your entity but I don't see how you would get that with stored procedures as well.
All in all it took me about 2 solid days to get this all up and running for us.

NHibernate thread-safe way of checking if entity exists

I've been banging my head off what should be a simple issue. I'm trying to do the following basic operation
1) Check if entity exists by a field other than ID
2) If not, create entity
Problem is this is in a console app that is multi-threaded, so I need to somehow get an entity by a field other than the ID and set the LockMode to Upgrade (or at least I think thats what needs to be done). From what I see there is no way to do that with ISession.
Any ideas?
in a single process use a global lockobject
lock(existsLocker)
{
var entity = session.Query<Entity>().Where(...).FirstOrDefault();
if (entity == null)
{
entity = new Entity();
session.Save(entity);
session.Flush();
}
}

MVC 4 Lookup UserName Based on UserId

I'm using the MVC 4 template with VS 2012. I have enabled a comments section which stores the logged in user's UserId to a table. When I display the comments I want to display the user's user name and email from the UserProfiles table.
I've tried the following code:
public static string GetUserName(int userId)
{
using (var db = new UsersContext())
{
return db.UserProfiles.Single(x => x.UserId == userId).UserName;
}
}
But I get an exception:
The model backing the 'UsersContext' context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).
Any suggestions?
The exception is pretty descriptive. Your model does not reflect what your database look like. I recommend you to read this about code first migrations, basically what migrations mean is that you update your database to match your models, its done with one line of command in VS.
Hope this helps
Also I would recommend you to use .Find() or .First() instead of .Single()

Why does NHibernate need to know the ID of an auto ID based entity before flush is called?

With my only ORM knowledge being L2S/EF, I was surprised when the following code inserted a row into the database before I called repo.Save:
var repo = new UserRepository();
var user = new User { Name = "test" }
repo.Add(user);
//repo.Save();
Repo looks like this:
public void Add(T entity)
{
session.Save(entity);
}
public void Save()
{
session.Flush();
}
After some digging, it seems NHibernate needs to make the insert happen right away in order to get the ID of the new entity (since it's using an auto increment ID). But L2S/EF doesn't work like this; I can add many entities and save them all at the end.
Question is: is there a way to achieve the same thing with NHibernate, while still using auto increment IDs, and out of interest does anyone know why it works like this?
Fabio Maulo already blogged about the usage of identity generator a few times. The answer is: use hilo, guid.comb or something like this.
NHibernate needs the identity because every entity in the session (they are called "persistent entities") needs to be identified. The identity is also normally used to determine if the record already exists in the database (unsaved value).
session.Save actually only makes a transient entity persistent. When the database is generating the id, it needs to be stored to get the id. If NH can create the id itself (eg using hilo), it could be stored next time when the session gets flushed.