Let's assume I have an instance of this class.
public class MyClass
{
public string LocationCode;
public string PickUpCode
}
There is another class that takes a List<MyClass> as input and saves to the DB.
Now I need to apply some business rules:
For example if LocationCode is null this item in the List<MyClass> must be skipped and the foreach loop must continue to the next item in the list.
I've written the following code and the items with null LocationCode are indeed skipped but the var instance = new SomeClass(); somehow remains in memory so when the loop reaches an valid item and proceeds to save it in the DB, it also saves all the previously skipped instances of var instance = new SomeClass();. Which means I have null entries in the DB.
I'm using NHibernate and Evictdoesn't seam to be doing the trick. Any suggestions?
public void Save(List<MyClass> listOfItems)
{
using (UnitOfWork.Start())
{
var repository = new Repository();
try
{
foreach (var item in listOfItems.Select(i => i.Item).Where(item => item != null))
{
var instance = new SomeClass();
if (pickUpCode != null)
{
instance.PickUpCode = pickUpCode;
}
else
{
instance.PickUpCode = null;
}
if (locationCode != null)
{
instance.StartLocation = locationCode
}
else
{
UnitOfWork.CurrentSession.Evict(instance);
continue;
}
repository.SaveSomeClass(instance);
}
}
catch (Exception ex)
{
_log.Error(" Unhandled error", ex);
}
}
}
** Because someone asked, here's some code on UnitOfWork.Start()
public static class UnitOfWork
{
public static IUnitOfWork Start();
}
public interface IUnitOfWork : IDisposable
{
bool IsInActiveTransaction { get; }
IUnitOfWorkFactory SessionFactory { get; }
IGenericTransaction BeginTransaction();
IGenericTransaction BeginTransaction(IsolationLevel isolationLevel);
void Flush();
void TransactionalFlush();
void TransactionalFlush(IsolationLevel isolationLevel);
}
Why don't you fail first and avoid all of this?
Example being:
foreach (var item in listOfItems.Select(i => i.Item).Where(item => item != null))
{
if (item.LocationCode == null){
continue;
}
var instance = new SomeClass();
if (pickUpCode != null)
{
instance.PickUpCode = pickUpCode;
}
else
{
instance.PickUpCode = null;
}
// if we reach here, location code is definitley not null, no need for the check
instance.StartLocation = locationCode
repository.SaveSomeClass(instance);
}
Alternatively, you could add the check to you LINQ where clause
foreach (var item in listOfItems.where(item=> item != null && item.LocationCode != null)
Without more code on how UnitofWork.Start works its hard to suggest. But, It's worth trying by implementing IDisposable on SomeClass.
Related
I have the Cache layer described below. The problem is that I need to get Lists or specific element from List, and then modify it, then persist it to db, and update the cache list.
So to avoid problems between the cache layer & DB layer, when getting data from cache I should make/get a copy of it, so it doesn't get changed down the way (if it's changes DB layer throws an error).
Question is how to properly approach this copy strategy, and other question is should the lock be present for add/remove operations too? (if yes, what is the right way to lock prior to modify?)
The cache is a singleton DI through services.
services.AddSingleton<MyCache>();
public class MyCache
{
private readonly AsyncLock _mutex = new AsyncLock();
public MemoryCache Cache { get; set; }
public MyCache()
{
Cache = new MemoryCache(new MemoryCacheOptions());
// populate cache from DB
}
public async Task<List<UDT>> GetUDTsForUser(string id, bool fetchFromDB = false)
{
List<UDT> list = new List<UDT>();
Cache.TryGetValue(id, out list);
if (list == null)
{
using (await _mutex.LockAsync())
{
Cache.TryGetValue(id, out list);
if (list == null && fetchFromDB)
{
var DAO = new DAO();
list = (await DAO.GetInfoForUser(id))?.UDTs;
if (list != null)
{
Cache.Set(id, list);
}
}
}
}
return list;
}
public async Task<UDT> GetUDTForUser(string id, long udtId)
{
List<UDT> list = new List<UDT>();
Cache.TryGetValue(id, out list);
if (list == null)
{
using (await _mutex.LockAsync())
{
Cache.TryGetValue(id, out list);
if (list == null)
{
var DAO = new DAO();
list = (await DAO.GetInfoForUser(id)).UDTs;
Cache.Set(id, list);
return list.FirstOrDefault(u => u.Id == udtId);
}
}
}
return list.FirstOrDefault(u => u.Id == udtId);
}
public void AddElement(UDT udt)
{
if (udt == null)
return;
var udtList = Cache.GetOrCreate(udt.GroupId, entry => {
return new List<UDT>();
});
if (udtList.Contains(udt) == false)
{
udtList.Add(udt);
Cache.Set(udt.GroupId, udtList);
}
}
public void RemoveElement(string groupId, long udtId)
{
var udtList = Cache.Get<List<UDT>>(groupId);
if (udtList != null)
{
udtList.RemoveAll(e => e.Id == udtId);
Cache.Set(groupId, udtList);
}
}
}
I have fields for audit trail in each table (InsertedBy, InsertedDate, UpdatedBy and UpdatedDate), I build solution to reduce redundant before by override savechange():
public override int SaveChanges()
{
foreach (var entry in ChangeTracker.Entries().Where(e =>
e.State == System.Data.Entity.EntityState.Added || e.State == System.Data.Entity.EntityState.Modified))
{
Auditing.ApplyAudit(entry, User);
}
return base.SaveChanges();
}
public class Auditing
{
public static void ApplyAudit(DbEntityEntry entityEntry, int User)
{
Type type = entityEntry.Entity.GetType();
if (entityEntry.State.ToString() == "Added")
{
if (type.GetProperty("InsertedBy") != null)
{
entityEntry.Property("InsertedBy").CurrentValue = User;
}
if (type.GetProperty("InsertedDate") != null)
{
entityEntry.Property("InsertedDate").CurrentValue = DateTime.Now;
}
}
else if (entityEntry.State.ToString() == "Modified")
{
if (type.GetProperty("InsertedBy") != null)
{
entityEntry.Property("InsertedBy").IsModified = false;
}
if (type.GetProperty("InsertedDate") != null)
{
entityEntry.Property("InsertedDate").IsModified = false;
}
if (type.GetProperty("UpdatedBy") != null)
{
entityEntry.Property("UpdatedBy").CurrentValue = User;
}
if (type.GetProperty("UpdatedDate") != null)
{
entityEntry.Property("UpdatedDate").CurrentValue = DateTime.Now;
}
}
}
}
the question is:
is using reflection within each entity before modified or added waste in memory and performance ? if yes is there is best practice for this ?
is this another code snippet better in performance or just use reflection also?
public static void ApplyAudit(DbEntityEntry entityEntry, long User)
{
if (entityEntry.State.ToString() == "Added")
{
entityEntry.Property("InsertedBy").CurrentValue = User;
entityEntry.Property("InsertedDate").CurrentValue = DateTime.Now;
}
else if (entityEntry.State.ToString() == "Modified")
{
entityEntry.Property("InsertedBy").IsModified = false;
entityEntry.Property("InsertedDate").IsModified = false;
entityEntry.Property("UpdatedBy").CurrentValue = User;
entityEntry.Property("UpdatedDate").CurrentValue = DateTime.Now;
}
}
is entityEntry.Property("InsertedBy") uses reflection ?
Reflection is slow (slow is subjective) and if you want to avoid it, then you need to get rid of such code as below:
Type type = entityEntry.Entity.GetType();
if (type.GetProperty("InsertedBy") != null)
Even if it was not slow, the code above is still "buggy" because a programmer may mistakenly write InsertBy instead of InsertedBy. This can easily be avoided with help from the compiler using the approach below.
Use an interface and implement it in all entities that require audit.
public interface IAuditable
{
string InsertedBy { get; set; }
// ... other properties
}
public class SomeEntity : IAuditable
{
public string InsertedBy { get; set; }
}
public class Auditor<TAuditable> where TAuditable : IAuditable
{
public void ApplyAudit(TAuditable entity, int userId)
{
// No reflection and you get compiler support
if (entity.InsertedBy == null)
{
// whatever
}
else
{
// whatever
}
}
}
As mentioned in the comments, you will get compiler support and reflection is not used anymore. I would even go a step further and not pass the int userId. I will bring the code for figuring out the userId and put it in this class. That way the class is self sufficient and clients do not need to provide it this information.
Usage:
var e = new SomeEntity();
var auditor = new Auditor<SomeEntity>();
auditor.ApplyAudit(e, 1); // 1 is userId, I am just hardcoding for brevity
Or use it from your context:
public override int SaveChanges()
{
var auditables = ChangeTracker.Entries().Where(e =>
e.State == System.Data.Entity.EntityState.Added || e.State == System.Data.Entity.EntityState.Modified)
.OfType<IAuditable>();
var auditor = new Auditor<IAuditable>();
foreach (var entry in auditables)
{
// 1 is userId, I am just hardcoding for brevity
auditor.ApplyAudit(entry, 1);
}
return base.SaveChanges();
}
This means that all entities who are auditable will need to implement the IAuditable interface. EF generates partial classes for your entities but do not modify those partial classes because the next time you run the custom tool, it will be wiped out.
Instead, create another partial class with the same name and implement the IAuditable.
public partial class SomeEntity : IAuditable {}
An even better approach is to create a custom T4 template so it creates the partial class with the code : IAuditable. Please see this article for how to do that.
I have a class that should track the last time it was accessed and I have a public property that exposes that last access time value which is set privately.
My class is defined as follows:
internal class DeviceModelCacheItem
{
private int _cacheId;
private List<DeviceModel> _deviceModels;
private DateTime _lastAccess;
public DeviceModelCacheItem(int cacheId, List<DeviceModel> deviceModels)
{
_cacheId = cacheId;
_deviceModels = deviceModels;
_lastAccess = DateTime.UtcNow;
}
...
public List<DeviceModel> DeviceModels
{
get
{
_lastAccess = DateTime.UtcNow;
return _deviceModels;
}
set
{
_lastAccess = DateTime.UtcNow;
_deviceModels = value;
}
}
public DateTime LastAccess
{
get
{
return _lastAccess;
}
}
}
I am accessing this value in a seperate class method as follows:
var cacheItem = _deviceModelCache.SingleOrDefault(x => x.CacheId == deviceTypeId);
if(cacheItem != null && DateTime.UtcNow.Subtract(cacheItem.LastAccess).TotalSeconds > 120)
{
...
}
Where _deviceModelCache is a collection of DeviceModelCacheItem instances.
I'm finding that whenever I try and access this value, the private value will always be updated making it impossible to use it as a tracking value. Why is this being updated?
EDIT
I've included more code showing how I'm access the DateTime value. The collection of DeviceModelCacheItem instances are held in a singleton as follows:
EDIT 2
I've as also added the db access code and also included where I'm updating the _lastAccess property. I figure I may have a deferred execution problem.
public class DeviceModelRepository
{
private List<DeviceModelCacheItem> _deviceModelCache;
private static readonly Lazy<DeviceModelRepository> instance = new Lazy<DeviceModelRepository>(() => new DeviceModelRepository());
public static DeviceModelRepository Instance
{
get
{
return instance.Value;
}
}
private DeviceModelRepository()
{
_deviceModelCache = new List<DeviceModelCacheItem>();
}
public IEnumerable<DeviceModel> GetAllDeviceModelsByDeviceTypeId(int deviceTypeId)
{
return GetAllDeviceModelsByDeviceTypeId(GlobalConfiguration.APP_CACHE_ENABLED, deviceTypeId);
}
private IEnumerable<DeviceModel> GetAllDeviceModelsByDeviceTypeId(bool enableCache, int deviceTypeId)
{
var cacheItem = _deviceModelCache.SingleOrDefault(x => x.CacheId == deviceTypeId);
//Debugger attached here
if(cacheItem != null && DateTime.UtcNow.Subtract(cacheItem.LastAccess).TotalSeconds > 120)
{
...
using (GadgetContext db = new GadgetContext())
{
var deviceModels = db.DeviceModels.Where(x => x.DeviceTypeId == deviceTypeId).ToList();
if (enableCache && deviceModels != null && deviceModels.Count > 0)
{
try
{
if(cacheItem == null)
{
_deviceModelCache.Add(new DeviceModelCacheItem(deviceTypeId, deviceModels));
}
else
{
cacheItem.DeviceModels = deviceModels;
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.ToString());
}
}
}
...
}
...
}
}
As pointed out by #JamesLucas the issue of the DateTime.UtcNow value always being updated was down to a deferred execution error in my code. My date time value was being updated every time entity framework deferred execution to grab items from the DB.
I'm writing a ReSharper 7.1 Generator plugin and need to get a list of all types declared in the current project (classes, interfaces and structs - IDeclaredType-s) for the GeneratorProviderBase<CSharpGeneratorContext>.Populate method.
With regular reflection it would be as simple as Assembly.GetTypes(), but here it's proven to be quite a challenge. Is there a way to do this?
I've searched high and low, the docs and samples didn't help, then looked through every *Extensions and *Util class, but couldn't find anything useful...
I managed to do what I needed, but I'm not really sure if it's the right/best approach:
[GeneratorElementProvider("MyGeneratorProvider", typeof(CSharpLanguage))]
public class MyGeneratorProvider : GeneratorProviderBase<CSharpGeneratorContext>
{
public override double Priority
{
get { return 0; }
}
public override void Populate(CSharpGeneratorContext context)
{
var projectCsFiles = GetAllCSharpFilesInProject(context.PsiModule);
var declarations = projectCsFiles.SelectMany(GetDeclarationsFromCSharpFile).ToList();
context.ProvidedElements.AddRange(declarations.Select(d => new GeneratorDeclarationElement(d)));
}
private static IEnumerable<ICSharpFile> GetAllCSharpFilesInProject(IPsiModule projectModule)
{
PsiManager psiManager = projectModule.GetPsiServices().PsiManager;
return projectModule.SourceFiles.SelectMany(f => psiManager.GetPsiFiles<CSharpLanguage>(f).OfType<ICSharpFile>());
}
private static IEnumerable<ITypeDeclaration> GetDeclarationsFromCSharpFile(ICSharpFile file)
{
return file.NamespaceDeclarationNodes.SelectMany(GetDeclarationsFromCSharpNamespace);
}
private static IEnumerable<ITypeDeclaration> GetDeclarationsFromCSharpNamespace(ICSharpNamespaceDeclaration namespaceDeclaration)
{
foreach (var namespaceChild in namespaceDeclaration.Body.Children())
{
var classDeclaration = namespaceChild as IClassDeclaration;
if (classDeclaration != null)
{
yield return classDeclaration;
}
else
{
var childNamespace = namespaceChild as ICSharpNamespaceDeclaration;
if (childNamespace != null)
{
foreach (var declaration in GetDeclarationsFromCSharpNamespace(childNamespace))
{
yield return declaration;
}
}
}
}
}
}
Any comments or simpler (maybe even built-in) ways of doing this?
Here's what I came up with using the cache. It still doesn't seem right, but I expect it to be better than the previous approach. This is still called from a GeneratorProvider.Populate:
public static IEnumerable<ICSharpTypeDeclaration> GetAllPublicTypeDeclarations(this IPsiModule module)
{
var declarationCache = module.GetPsiServices().CacheManager.GetDeclarationsCache(module, false, true);
var declarations = new List<ICSharpTypeDeclaration>();
foreach (var shortName in declarationCache.GetAllShortNames())
{
var declaredElements = declarationCache.GetElementsByShortName(shortName).OfType<ITypeElement>().Where(e =>
{
var elementType = e.GetElementType();
return elementType == CLRDeclaredElementType.CLASS || elementType == CLRDeclaredElementType.INTERFACE || elementType == CLRDeclaredElementType.ENUM;
});
foreach (ITypeElement declaredElement in declaredElements)
{
var declaration = declaredElement.GetDeclarations().OfType<ICSharpTypeDeclaration>().FirstOrDefault(d => d.GetAccessRights() == AccessRights.PUBLIC);
if (declaration != null)
{
declarations.Add(declaration);
}
}
}
return declarations;
}
Note: The results won't be the same as in the first answer, cause I've changed some restrictions. Also, in both cases, I'm not concerned with partial classes.
I'm updating an ObservableCollection of a WPF ViewModel in a WCF Data Service asynchronous query callback method:
ObservableCollection<Ent2> mymodcoll = new ObservableCollection<Ent2>();
...
query.BeginExecute(OnMyQueryComplete, query);
...
private void OnMyQueryComplete(IAsyncResult result)
{
...
var repcoll = query.EndExecute(result);
if (mymodcoll.Any())
{
foreach (Ent c in repcoll)
{
var myItem = mymodcoll.Where(p => p.EntID == c.EntID).FirstOrDefault();
if (myItem != null)
{
myItem.DateAndTime = c.DateAndTime; // here no problems
myItem.Description = c.Description;
...
}
else
{
mymodcoll.Add(new Ent2 //here I get a runtime error
{
EntID = c.EntID,
Description = c.Description,
DateAndTime = c.DateAndTime,
...
});
}
}
}
else
{
foreach (Ent c in repcoll)
{
mymodcoll.Add(new Ent2 //here, on initial filling, there's no error
{
EntID = c.EntID,
Description = c.Description,
DateAndTime = c.DateAndTime,
...
});
}
}
}
The problem is, when a query result collection contains an item which is not present in the target collection and I need to add this item, I get a runtime error: The calling thread cannot access this object because a different thread owns it. (I pointed out this line of code by a comment)
Nevertheless, if the target collection is empty (on initial filling) all items have been added without any problem. (This part of code I also pointed out by a comment). When an item just needs to update some of its fields, there are no problems as well, the item gets updated ok.
How could I fix this issue?
First case: Here you a modifying an object in the collection, not the collection itself - thus the CollectionChanged event isn't fired.
Second case: here you are adding a new element into the collection from a different thread, the CollectionChanged event is fired. This event needs to be executed in the UI thread due to data binding.
I encountered that problem several times already, and the solution isn't pretty (if somebody has a better solution, please tell me!). You'll have to derive from ObservableCollection<T> and pass it a delegate to the BeginInvoke or Invoke method on the GUI thread's dispatcher.
Example:
public class SmartObservableCollection<T> : ObservableCollection<T>
{
[DebuggerStepThrough]
public SmartObservableCollection(Action<Action> dispatchingAction = null)
: base()
{
iSuspendCollectionChangeNotification = false;
if (dispatchingAction != null)
iDispatchingAction = dispatchingAction;
else
iDispatchingAction = a => a();
}
private bool iSuspendCollectionChangeNotification;
private Action<Action> iDispatchingAction;
[DebuggerStepThrough]
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (!iSuspendCollectionChangeNotification)
{
using (IDisposable disposeable = this.BlockReentrancy())
{
iDispatchingAction(() =>
{
base.OnCollectionChanged(e);
});
}
}
}
[DebuggerStepThrough]
public void SuspendCollectionChangeNotification()
{
iSuspendCollectionChangeNotification = true;
}
[DebuggerStepThrough]
public void ResumeCollectionChangeNotification()
{
iSuspendCollectionChangeNotification = false;
}
[DebuggerStepThrough]
public void AddRange(IEnumerable<T> items)
{
this.SuspendCollectionChangeNotification();
try
{
foreach (var i in items)
{
base.InsertItem(base.Count, i);
}
}
finally
{
this.ResumeCollectionChangeNotification();
var arg = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
this.OnCollectionChanged(arg);
}
}
}