Avoid locking an Object that's already in the session (UniqueObjectException) - c#

I call this function on my objects when they need to be initialized again:
public virtual void Initialize()
{
if (!HibernateSessionManager.Instance.GetSession().Contains(this)) {
try
{
HibernateSessionManager.Instance.GetSession()
.Lock(this, NHibernate.LockMode.None);
}
catch (NonUniqueObjectException e) { }
}
}
I thought I can prevent initializing something twice with checking Contains(this), but it happens sometimes that Lock(this, NHibernate.LockMode.None) throws a NonUniqueObjectException. So far I ignore it because it works, but I'd like to know the reason and a better way to Lock my objects.
Best regards, Expecto

This most likely means you violate the Identity map somewhere. This means you have two instances of an object hanging around with the same database ID, but different referential identity.
Session.Contains will check reference equality, but Lock will throw an exception if there's anything with the same type & id already in the session, which is a much less strict comparison.
Consider the following test on the AdventureWorks database, with a (very naive and unrecommended) simple implementation of Equals & GetHashCode
using (ISession session = SessionFactory.Factory.OpenSession())
{
int someId = 329;
Person p = session.Get<Person>(someId);
Person test = new Person() { BusinessEntityID = someId };
Assert.IsTrue(p.Equals(test)); //your code might think the objects are equal, so you'd probably expect the next line to return true
Assert.IsFalse(session.Contains(test)); //But they're not the same object
Assert.Throws<NonUniqueObjectException>(() =>
{
session.Lock(test, LockMode.None); //So when you ask nhibernate to track changes on both objects, it gets very confused
});
}
NHibernate (and I'd guess any ORM) works by tracking changes to objects. So in Get'ing Person 329, you ask NHibernate to pay attention to whatever happens to that particular instance of a Person. Let's say we change his first-name to Jaime.
Next, we get another instance of person with the same Id (in this case we just new'ed it up, but there are many insidious ways to get such an object). Imagine NHibernate would let us attach this to the session as well. We could even set the first-name of this second object to something like Robb.
When we flush the session NHibernate has no way of knowing whether the database row needs to be synched to either Robb or Jaime. So it throws the non-unique your way before that could happen.
Ideally these situations shouldn't crop up, but if you're very sure what's happening, you might want to check out session.Merge, which lets you force the tracked state to whatever happens to be merged in last (Robb in the example).

the problem was a completely different - contains checks for equality by reference if I don't override Equals(). Now it works with the code from my question!
public override bool Equals(object obj)
{
if (this == obj) {
return true;
}
if (GetType() != obj.GetType()) {
return false;
}
if (Id != ((BaseObject)obj).Id)
{
return false;
}
return true;
}

Related

What is pattern for Find Or Create database item?

If there is one, what is the C# idiom for Find-Or-Create? Pseudocode:
private IEntity FindOrCreateEntity(int id, object properties)
{
Entity foundEntity = _db.Find(id);
if (foundEntity == null)
{
foundEntity = _db.Create<Entity>(properties);
}
return foundEntity;
}
I don't like find and create being in the same method.
I don't like find and create being in the same method.
Then don't do it?
You now have a method that takes either an ID of an object to look up, or a bunch of properties to populate a new instance with. That's confusing, to say the least.
What if the caller thinks the ID should return an exisiting record, but it doesn't exist (anymore)? It'll then live on under the assumption it's working on an existing record, while in fact the record does not exist in the databaes yet.
Just let the caller adhere to this pattern:
var entity = _repository.Find(id);
if (entity == null)
{
entity = _repository.Create();
}
If anyhting, you can give IEntity's implementation an IsNew property, which returns whether Id == default(TId).

Ignore null values in context update

I have a large model which has been partially updated via deserialization. Since it has only been partially updated I would like to ignore any null values when I pass this to my entity framework update. Ultimately the EntityState.Modified is set but the issue I am having is that all fields are updated. This means anything that was null is now blanked in the database.
Is it possible to change this default behavior through a setting or override a method to check for null? It seems that since the context is expecting the full model I cannot simply set only a few values.
I've verified this by mapping only what I need to modify and the same behavior occurs.
You could implement something like this.
In this case I'm using a generic repository with reflection, to iterate through the properties and exclude null values in the update method.
public virtual TEntity Update(TEntity entity)
{
dbSet.Attach(entity);
dbContext.Entry(entity).State = EntityState.Modified;
var entry = dbContext.Entry(entity);
Type type = typeof(TEntity);
PropertyInfo[] properties = type.GetProperties();
foreach (PropertyInfo property in properties)
{
if (property.GetValue(entity, null) == null)
{
entry.Property(property.Name).IsModified = false;
}
}
dbContext.SaveChanges();
return entity;
}
public IHttpActionResult PutProduct(int id, Product product)
{
NorthwindEntities db = new NorthwindEntities();
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Products.Attach(product);
// Only the fields you want to update, will change.
db.Entry(product).Property(p => p.ProductName).IsModified = true;
db.Entry(product).Property(p => p.UnitPrice).IsModified = true;
db.Entry(product).Property(p => p.UnitsInStock).IsModified = true;
// only if if the value is not null, the field will change.
db.Entry(product).Property(p => p.UnitsOnOrder).IsModified =
product.UnitsOnOrder != null;
db.SaveChanges();
return Ok(product);
}
This is a somewhat tedious problem I've had to solve.
For lack of a more straightforward solution, eventually I decided I'd rather not want to try solving it as much downstream as when EF's SaveChanges-and-the-likes' get called (i.e., no need to "hook into" EF so late), but instead as much higher upstream / earlier on as possible --
that is, to do so right after I obtain a satisfying deserialization, which is meaningful to mutate the model, on a per-entity instance basis (in my use case, none of the updatable properties would represent relationships, but only independent attributes, in E/R parlance -- YMMV)
So, I opted for a "Populate" helper, along the lines of:
static void Populate(object from, object to)
{
var sourceType = from.GetType();
foreach (PropertyInfo target in to.GetType().GetProperties())
{
// Is the property at the target object writable and *not* marked
// as `[NotMapped]'?
var isUpdatable =
target.CanWrite &&
(target.GetCustomAttribute<NotMappedAttribute>(true) == null);
if (isUpdatable)
{
// If so, just find the corresp. property with the same name at the source object
// (caller is assumed responsible to guarantee that there is one, and of the same type, here)
var source = sourceType.GetProperty(target.Name);
var #default = sourceType.IsValueType ? Activator.CreateInstance(sourceType) : null;
var equality = (IEqualityComparer)typeof(EqualityComparer<>).MakeGenericType(sourceType).GetProperty("Default", BindingFlags.Public | BindingFlags.Static).GetValue(null);
var value = source.GetValue(from);
// Test for <property value> != default(<property type>)
// (as we don't want to lose information on the target because of a "null" (or "default(...)") coming from the source)
if (!equality.Equals(value, #default))
{
target.SetValue(to, value, null);
}
}
}
}
where "from" is the fresh entity instance that just got partially populated by whatever deserialization code, and where "to" is the actual target entity that lives in the DbContext (be it an EF proxy or not);
and where NotMappedAttribute is the EF's usual.
You'd typically have Populate to be called some time after the deserialization (&/or DTO-mapping) onto your "from" instance is done, but anyway before SaveChanges() gets call on your DbContext for all the "to" entities -- obviously, we assume there is a feasible 1-to-1 mapping "from" ... "to", that the caller of Populate knows about / could figure out.
Note I still don't know if there is a more elegant (more straightforward) way to do that, without recourse to reflection -- so, there, FWIW.
Remarks
1) above code can (or should) be made more defensive in various ways, depending on the caller assumptions;
2) one may want to cache those IEqualityComparer's (&/or the PropertyInfo's) for whatever (good) reason may arise -- in my case, I didn't have to;
3) finally, my understanding is that third-party librairies such as AutoMapper are also specially designed for that sort of task, if you can afford the additional dependency
'HTH,

Retrieved Dictionary Key Not Found

I have a SortedDictionary declared like such:
SortedDictionary<MyObject,IMyInterface> dict = new SortedDictionary<MyObject,IMyInterface>();
When its populated with values, if I grab any key from the dictionary and then try to reference it immediately after, I get a KeyNotFoundException:
MyObject myObj = dict.Keys.First();
var value = dict[myObj]; // This line throws a KeyNotFoundException
As I hover over the dictionary (after the error) with the debugger, I can clearly see the same key that I tried to reference is in fact contained in the dictionary. I'm populating the dictionary using a ReadOnlyCollection of MyObjects. Perhaps something odd is happening there? I tried overriding the == operator and Equals methods to get the explicit comparison I wanted, but no such luck. That really shouldn't matter since I'm actually getting a key directly from the Dictionary then querying the Dictionary using that same key. I can't figure out what's causing this. Has anyone ever seen this behavior?
EDIT 1
In overriding Equals I also overloaded (as MS recommends) GetHashCode as well. Here's the implementation of MyObject for anyone interested:
public class MyObject
{
public string UserName { get; set;}
public UInt64 UserID { get; set;}
public override bool Equals(object obj)
{
if (obj == null || GetType()!= obj.GetType())
{
return false;
}
// Return true if the fields match:
return this.Equals((MyObject)obj);
}
public bool Equals(MyObject other)
{
// Return true if the fields match
return this.UserID == other.UserID;
}
public override int GetHashCode()
{
return (int)this.UserID;
}
public static bool operator ==( MyObject a, MyObject b)
{
// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))
{
return true;
}
// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))
{
return false;
}
// Return true if the fields match:
return a.UserID == b.UserID
}
public static bool operator !=( MyObject a, MyObject b)
{
return !(a == b);
}
}
What I noticed from debugging is that if I add a quick watch (after the KeyNotFoundException is thrown) for the expression:
dict.ElementAt(0).Key == value;
it returns true. How can this be?
EDIT 2
So the problem ended up being because SortedDictionary (and Dictionary as well) are not thread-safe. There was a background thread that was performing some operations on the dictionary which seem to be triggering a resort of the collection (adding items to the collection would do this). At the same time, when the dictionary iterated through the values to find my key, the collection was being changed and it was not finding my key even though it was there.
Sorry for all of you who asked for code on this one, I'm currently debugging an application that I inherited and I didn't realize this was going on on a timed, background thread. As such, I thought I copied and pasted all the relevant code, but I didn't realize there was another thread running behind everything manipulating the collection.
It appears that the problem ended up being because SortedDictionary is not thread-safe. There was a background thread that was performing some operations on the dictionary (adding items to the collection) which seems to be triggering a resort of the collection. At the same time, when the dictionary was attempting to iterate through the values to find my key, the collection was being changed and resorted, rendering the enumerator invalid, and it was not finding my key even though it was there.
I have a suspicion - it's possible that you're changing the UserID of the key after insertion. For example, this would demonstrate the problem:
var key = new MyObject { UserId = 10 };
var dictionary = new Dictionary<MyObject, string>();
dictionary[key] = "foo";
key.UserId = 20; // This will change the hash code
var value = dict[key]; // Bang!
You shouldn't change properties involved in equality/hash-code considerations for an object which is being used as the key in a hash-based collection. Ideally, change your code so that this can't be changed - make UserId readonly, initialized on construction.
The above definitely would cause a problem - but it's possible that it's not the same as the problem you're seeing, of course.
In addition to overloading == and Equals, make sure you override GetHashCode with a suitable hash function. In particular, see this specification from the documentation:
If two objects compare as equal, the GetHashCode method for each object must return the same value. However, if two objects do not
compare as equal, the GetHashCode methods for the two objects do not
have to return different values.
The GetHashCode method for an object must consistently return the same hash code as long as there is no modification to the object state
that determines the return value of the object's Equals method. Note
that this is true only for the current execution of an application,
and that a different hash code can be returned if the application is
run again.
For the best performance, a hash function should generate an even distribution for all input, including input that is heavily clustered.
An implication is that small modifications to object state should
result in large modifications to the resulting hash code for best hash
table performance.
Hash functions should be inexpensive to compute.
The GetHashCode method should not throw exceptions.
I agree with Jon Skeet's suspicion that you're somehow unintentionally modifying UserID property after it's added as a key. But since the only property that's important for testing equality in MyObject is UserID (and therefore that's the only property that the Dictionary cares about), I'd recommend refactoring your code to use a simple Dictionary<ulong, IMyInterface> instead:
Dictionary<ulong, IMyInterface> dict = new Dictionary<string, IMyInterface>();
ulong userID = dict.Keys.First();
var value = dict[userID];

A generic way to save an entity in Entity Framework

I am trying to write a GenericEFRepository which will be used by other Repositories. I have a Save method as below.
public virtual void Save(T entity) // where T : class, IEntity, new() And IEntity enforces long Id { get; set; }
{
var entry = _dbContext.Entry(entity);
if (entry.State != EntityState.Detached)
return; // context already knows about entity, don't do anything
if (entity.Id < 1)
{
_dbSet.Add(entity);
return;
}
var attachedEntity = _dbSet.Local.SingleOrDefault(e => e.Id == entity.Id);
if (attachedEntity != null)
_dbContext.Entry(attachedEntity).State = EntityState.Detached;
entry.State = EntityState.Modified;
}
You can find the problem in comments of below code
using (var uow = ObjectFactory.GetInstance<IUnitOfWork>()) // uow is implemented like EFUnitOfWork which gives the DbContext instance to repositories in GetRepository
{
var userRepo = uow.GetRepository<IUserRepository>();
var user = userRepo.Get(1);
user.Name += " Updated";
userRepo.Save(user);
uow.Save(); // OK only the Name of User is Updated
}
using (var uow = ObjectFactory.GetInstance<IUnitOfWork>())
{
var userRepo = uow.GetRepository<IUserRepository>();
var user = new User
{
Id = 1,
Name = "Brand New Name"
};
userRepo.Save(user);
uow.Save();
// NOT OK
// All fields (Name, Surname, BirthDate etc.) in User are updated
// which causes unassigned fields to be cleared on db
}
The only solution I can think of is creating Entities via repository like userRepo.CreateEntity(id: 1) and repository will return an Entity which is attached to DbContext. But this seems error prone, still any developer may create an entity using new keyword.
What are your solution suggestions about this particular problem?
Note: I already know about cons and pros of using a GenericRepository and an IEntity interface. So, "Don't use a GenericRepository, don't use an IEntity, don't put a long Id in every Entity, don't do what you are trying to do" comments will not help.
Yes it is error prone but simply that is the problem with EF and repositories. You must either create entity and attach it before you set any data you want to update (Name in your case) or you must set modified state for each property you want to persist instead of whole entity (as you can imagine again developer can forget to do that).
The first solution leads to special method on your repository doing just this:
public T Create(long id) {
T entity = _dbContext.Set<T>().Create();
entity.Id = id;
_dbContext.Set<T>().Attach(entity);
return entity;
}
The second solution needs something like
public void Save(T entity, params Expression<Func<T, TProperty>>[] properties) {
...
_dbContext.Set<T>().Attach(entity);
if (properties.Length > 0) {
foreach (var propertyAccessor in properties) {
_dbContext.Entry(entity).Property(propertyAccessor).IsModified = true;
}
} else {
_dbContext.Entry(entity).State = EntityState.Modified;
}
}
and you will call it like:
userRepository(user, u => u.Name);
This is kind of a fundamental problem of this approach because you expect the repository to magically know which fields you changed and which ones you didn't. Using null as a signal for "unchanged" does not work in case null is a valid value.
You'd need to tell the repository which fields you want to have written, for example sending a string[] with the field names. Or one bool for each field. I do not think this is a good solution.
Maybe you can invert the control flow like this:
var entity = repo.Get(1);
entity.Name += "x";
repo.SaveChanges();
That would allow change tracking to work. It is closer to how EF wants to be used.
Alternative:
var entity = repo.Get(1);
entity.Name += "x";
repo.Save(entity);
While the other two answers provide good insight into how perhaps you can avoid this issue I think its worth pointing out a couple of things.
What you are trying to do (ie a proxy entity update) is extremely EF-centeric and IMO actually doesn't make sense outside of the EF context and hence it doesnt make sense that a generic repository would be expected to behave in this way.
You actually haven't even gotten the flow quite right for EF, if you attach an object with a few fields already set EF will conciser what you told it to be the current DB state unless you modify a value or set a modified flag. To do what you are attempting without a select you would normally attach an object without the name and then set the name after attaching the ID object
Your approach is normally used for performance reasons, I would suggest that by abstracting over the top of an existing framework you are almost always going to suffer some logical performance degradation. If this is a big deal maybe you shouldn't be using a repository? The more you add to your repository to cater to performance concerns the more complex and restrictive it becomes and the harder it gets to provide more than one implementation.
All that being said I do think you can handle this particular case in a generic situation.
This is one possible way you could do it
public void UpdateProperty(Expression<Func<T,bool>> selector, FunctionToSetAProperty setter/*not quite sure of the correct syntax off the top of my head*/)
{
// look in local graph for T and see if you have an already attached version
// if not attach it with your selector value set
// set the property of the setter
}
Hope this makes some sense, I'm not by my dev box atm so I cant really do a working sample.
I think this is a better approach for a generic repository as it allows you to implement this same behavior in multiple different ways, the abovc may work for EF but there will be different methods if you have an in memory repository (for example). This approach allows you to implement different implementations that fulfill the intent rather than restrict your repository to only act like EF.

LINQ to SQL DAL, is this thread safe?

My code is written with C# and the data layer is using LINQ to SQL that fill/load detached object classes.
I have recently changed the code to work with multi threads and i'm pretty sure my DAL isn't thread safe.
Can you tell me if PopCall() and Count() are thread safe and if not how do i fix them?
public class DAL
{
//read one Call item from database and delete same item from database.
public static OCall PopCall()
{
using (var db = new MyDataContext())
{
var fc = (from c in db.Calls where c.Called == false select c).FirstOrDefault();
OCall call = FillOCall(fc);
if (fc != null)
{
db.Calls.DeleteOnSubmit(fc);
db.SubmitChanges();
}
return call;
}
}
public static int Count()
{
using (var db = new MyDataContext())
{
return (from c in db.Calls select c.ID).Count();
}
}
private static OCall FillOCall(Model.Call c)
{
if (c != null)
return new OCall { ID = c.ID, Caller = c.Caller, Called = c.Called };
else return null;
}
}
Detached OCall class:
public class OCall
{
public int ID { get; set; }
public string Caller { get; set; }
public bool Called { get; set; }
}
Individually they are thread-safe, as they use isolated data-contexts etc. However, they are not an atomic unit. So it is not safe to check the count is > 0 and then assume that there is still something there to pop. Any other thread could be mutating the database.
If you need something like this, you can wrap in a TransactionScope which will give you (by default) the serializable isolation level:
using(var tran = new TransactionScope()) {
int count = OCall.Count();
if(count > 0) {
var call = Count.PopCall();
// TODO: something will call, assuming it is non-null
}
}
Of course, this introduces blocking. It is better to simply check the FirstOrDefault().
Note that PopCall could still throw exceptions - if another thread/process deletes the data between you obtaining it and calling SubmitChanges. The good thing about it throwing here is that you shouldn't find that you return the same record twice.
The SubmitChanges is transactional, but the reads aren't, unless spanned by a transaction-scope or similar. To make PopCall atomic without throwing:
public static OCall PopCall()
{
using(var tran = new TrasactionScope())
using (var db = new MyDataContext())
{
var fc = (from c in db.Calls where c.Called == false select c).FirstOrDefault();
OCall call = FillOCall(fc);
if (fc != null)
{
db.Calls.DeleteOnSubmit(fc);
db.SubmitChanges();
}
return call;
}
tran.Complete();
}
}
Now the FirstOrDefault is covered by the serializable isolation-level, so doing the read will take a lock on the data. It would be even better if we could explicitly issue an UPDLOCK here, but LINQ-to-SQL doesn't offer this.
Count() is thread-safe. Calling it twice at the same time, from two different threads will not harm anything. Now, another thread might change the number of items during the call, but so what? Another thread might change the number of item a microsecond after it returns, and there's nothing you can do about it.
PopCall on the other hand, does has a possibility of threading problems. One thread could read fc, then before it reaches the SubmitChanges(), another thread may interceded and do the read & delete, before returning to the first thread, which will attempt to delete the already deleted record. Then both calls will return the same object, even though it was your intension that a row only be returned once.
Unfortunately no amount of Linq-To-Sql trickery, nor SqlClient isolation levels, nor System.Transactions can make the PopCall() thread safe, where 'thread safe' really means 'concurrent safe' (ie. when concurrency occurs on the database server, outside the controll and scope of the client code/process). And neither is any sort of C# locking and synchronization going to help you. You just need to deeply internalize how a relational storage engine works in order to get this doen correctly. Using tables as queues (as you do it here) is notoriously tricky , deadlock prone, and really hard to get it correct.
Even less fortunate, your solution is going to have to be platform specific. I'm only going to explain the right way to do it with SQL Server, and that is to leverage the OUTPUT clause. If you want to get a bit more details why this is the case, read this article Using tables as Queues. Your Pop operation must occur atomically in the database with a calls like this:
WITH cte AS (
SELECT TOP(1) ...
FROM Calls WITH (READPAST)
WHERE Called = 0)
DELETE
FROM cte
OUTPUT DELETED.*;
Not only this, but the Calls table has to be organized with a leftmost clustered key on the Called column. Why this is the case, is again explained in the article I referenced before.
In this context the Count call is basically useless. Your only way to check correctly for an item available is to Pop, asking for Count is just going to put useless stress on the database to return a COUNT() value which means nothing under a concurrent environment.

Categories

Resources