ASP.NET MVC 3 Database Context Querying - c#

I have my Database Context:
public class ProductContext : DbContext
{
public ProductContext() : base ("DefaultConnection") {}
public DbSet<Product> Products {get;set;}
}
and my Repository:
public class ProductRepository : IProductRepository
{
private ProductContext _dbContext = new ProductContext();
public IQueryable<Product> Products { get { return _dbContext.Products; } }
}
when I query my database in the Edit Action:
public ActionResult Edit(Guid id)
{
var item = _repository.Products.FirstOrDefault(x => x.Id.Equals(id));
return View(item);
}
I would usually use a ViewModel but this is purely to show the scenario.
When I query the database using the var item line, does EntityFramework change the state of that item.
Can I pass around that item through a multitude of Services in the Service Layer and then finally save it using my method:
public void SaveEntity<TEntity>(TEntity entityToSave) where TEntity : DbEntity
{
if (entityToSave.Id.Equals(Guid.Empty))
_dbContext.Set<TEntity>().Add(entityToSave);
else
_dbContext.Entry<TEntity>(entityToSave).State = EntityState.Modified;
_dbContext.SaveChanges();
}
It won't throw an exception saying that there is already a Entity with the same Id as the one you're trying to Save?

So after trial and error, it seems that this works perfectly fine, and it doesn't bring back any errors. There is one thing to look out for:
This navigation property:
public virtual Category Category { get;set; }
public Guid CategoryId { get;set; }
That could reside in the Product model has a little gotcha, that is:
When editing or saving a new Product, you should only set the CategoryId and not just the Category exclusively because you will get duplicate Category entries every time you edit or save if you use the a Category that already exist within the database...
I think you should the navigation property solely for your ease, not for use when modifying entities...

Related

What is the correct flow of requests when working with multiple viewModels on EF Core/MVVM?

Futher into my studies on MVVM I found an issue I can't understand, and I couldn't find (rather, I think I couldn't word my Google searches correctly) information specific to this situation:
I have the following entities:
public class Sale : EntityBase
{
public ICollection<SaleItem> SaleItems {get;set;}
}
public class SaleItem : EntityBase
{
public Sale Sale {get;set;}
public Stock Stock {get;set;}
public TaxType TaxType {get;set;}
}
public class Stock : EntityBase
{
public TaxType TaxType {get;set;}
public ICollection<Sale> SaleStocks {get;set;}
}
public class EntityBase
{
[Key]
public int ID {get;set;}
}
public TaxType
{
[Key]
public int TaxCode {get;set;}
public string Description {get;set;
}
TaxType is seeded by the database migrations. I'm using MySQL.
From what I've read on what is the Alternate for AddorUpdate method in EF Core?, to record a new entry on my database, I should just call _context.Update(Sale) and _context.SaveChangesAsync().
However I still can't understand what am I doing wrong on a simple CRUD:
User is directed to a viewModel:
SaleViewModel.cs
private SaleItemStore _saleItemStore;
public Sale Sale {get;set;} = new();
public ObservableCollection<SaleItem> SaleItems {get;set;} = new();
public SaleViewModel(IServiceProvider serviceProvider)
{
_saleItemStore = serviceProvider.GetRequiredService<SaleItemStore>();
SaveSale = new SaveSaleCommand(this, serviceProvider);
}
public class SaveSaleCommand()
{
public SaveSaleCommand(SaleViewModel saleViewModel, IServiceProvidere serviceProvider)
{
_parentViewModel = saleViewModel;
_saleDataService = serviceProvider.GetRequiredService<SalaDataService>();
}
public Execute()
{
foreach (SaleItem saleItem in SaleItems)
{
Sale.SaleItems.Add(saleItem);
}
_saleDataService.AddOrUpdate(Sale sale);
}
}
On a different viewModel, the user can select, among other properties, the TaxType, from a dropdown combobox. The combobox's ItemsSource is bound to TaxTypesList like:
SelectStockToSaleItemViewModel
private TaxTypeDataService _taxTypeDataService;
public SaleItem SaleItem {get;set;} = new();
public TaxType SelectedTaxType {get;set;}
public ObservableCollection<TaxType> TaxTypesList {get;} = new();
public SelectStockToSaleItemViewModel(IServiceProvider serviceProvider)
{
_taxTypeDataService = serviceProvider.GetRequiredService<TaxTypeDataService>();
SendSaleItemBack = new SendSaleItemBackCommand(this, serviceProvider);
Task.Run(FillLists);
}
public async Task FillLists()
{
foreach (TaxType taxType in await _taxTypeDataService.GetAllAsNoTracking())
{
TaxTypesList.Add(taxType);
}
}
public SendSaleItemBackCommand()
{
private SaleItemStore _saleItemStore;
public SendSaleItemBackCommand(SelectStockToSaleItemViewModel selectStockToSaleItemViewModel, IServiceProvider serviceProvider)
{
_parentViewModel = selectStockToSaleItemViewModel;
_saleItemStore = serviceProvider.GetRequiredService<SaleItemStore>();
}
public Execute()
{
_saleItemStore.Message = new SaleItem()
{
TaxType = _parentViewModel.SelectedTaxType
}
//Takes user back to previous ViewModel;
}
}
So, my idea is that on SelectStockToSaleItemViewModelthe user selects a TaxType from a combobox filled with _taxTypeDataService.GetAllAsNoTracking(), and when they execute SendSaleItemBackCommand, SaleItemStore has its property set to a SaleItem with the TaxType not null;
Afterwards, should the user add more SaleItems to Sale, they'll have to open SelectStockToSaleItemViewModel again, and do the process for each extra SaleItem they wand to add to Sale.
Finally, they will have to execute SaveSaleCommand, and I'd end up with a Sale and its associated SaleItems on my database.
My dataServices are:
public class SaleDataService
{
private MyDbContext _context;
public SaleDataService(IServiceProvider serviceProvider)
{
_context = serviceProvider.GetRequiredService<MyDbContext>();
}
public async Task<Sale> AddOrUpdate(Sale sale)
{
_context.Update(sale);
await _context.SaveChangesAsync();
return sale;
}
}
public class TaxTypeDataService
{
private MyDbContext _contex;
public TaxTypeDataService(IServiceProvider serviceProvider0
{
_context = serviceProvider.GetRequiredService<MyDbContext>();
}
public async Task<List<TaxType>> GetAllAsNoTracking()
{
return _context.Set<TaxType>().AsNoTracking().ToListAsync();
}
}
public class Messaging<TObject> : IMessaging<TObject>
{
public TObject Message { get; set; }
}
SaleItemStore is singleton. SelectStockToSaleItemViewModel, and SelectStockToSaleItemViewModel are transient; TaxTypeDataService and SaleDataService are scoped; As for the context,
public static IHostBuilder AddDbContext(this IHostBuilder host)
{
host.ConfigureServices((_, services) =>
{
string connString = $"MyConnString";
ServerVersion version = new MySqlServerVersion(new Version(8, 0, 23));
Action <DbContextOptionsBuilder> configureDbContext = c =>
{
c.UseMySql(connString, version, x =>
{
x.CommandTimeout(600);
x.EnableRetryOnFailure(3);
});
c.EnableSensitiveDataLogging();
};
services.AddSingleton(new AmbiStoreDbContextFactory(configureDbContext));
services.AddDbContext<AmbiStoreDbContext>(configureDbContext);
});
return host;
}
The issue happens when the user tries to save a Sale with two or more SaleItems using the same TaxType, as EF Core throws an "another instance of TaxType is already being tracked". I understand the TaxType starts being tracked when the first Sale.SaleItem is updated, but how do I deal with this issue?
According to The instance of entity type 'Product' cannot be tracked because another instance with the same key value is already being tracked and The instance of entity type cannot be tracked because another instance of this type with the same key is already being tracked I did fill the combobox with TaxType using an AsNoTracking call, but I don't think it applies to my situation. Also, they say to "flush" the tracked entries before updating by setting the context's tracked entries' states to Detached, but, again, TaxType starts being tracked while being saved. I've checked the context's tracked entries collection, and there is no mention of TaxTypebeing tracked at all before Update(Sale) is called.
The only way I can think of as a workaround is using Fluent API and setting the foreign key, rather than the property itself (i.e. TaxTypeId = SelectedTaxType.ID), which doesn't look like the best way to deal with this.
Alright, I read some more about EF Core and I think I understood "the recommended way".
Whenever working with data services and dependency injection, the entities must be loaded by the same context that will be using them to add or update the context's database.
My mistake was loading the collections used by the interface (comboboxes, drop downs and checkboxes) using AsNoTracking. What happened was that whenever I tried to add or update two entities that used the same AsNoTracking-obtained entity, EF Core (as it should) tried to add the entity to the context's change tracker. So when the second entity tried to add/update, it threw a The instance of entity type cannot be tracked because another instance of this type with the same key is already being tracked exception.
So the "correct flow" is to load a collection/list using the same context that will be using them. Either using a singleton dbContext for the whole application and not using AsNoTracking, which is not recommended due to the possibility of ending up with concurrent operations; or using scoped dbContext for each "unit-of-work", i.e. a single dialog to add a new record, or an updating window with a record pulled from the same instance of the context that will be saving it, and disposing of the context (and it's change tracker) after whatever you wanted to do has been dealt with.
One of the big mistakes I was making when using scoped contexts was creating one context to load a datagrid with entries, which, when double-clicked, would open a dialog (with a new scoped context) to edit it without releasing that record from the previous context, throwing the already being tracked exception.

Remove an entity without fetching it in the generic repository pattern entity framework

I am trying to delete an entity of Employee from the database which contains different tables like Employee, Project, Skills using a generic repository pattern.
namespace Information.Repository
{
public class IRepositoy<TEntity> : IRepository<TEntity> where TEntity : class
{
private readonly ApplicationDbContext _dbContext;
public IRepositoy(ApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public void Remove(int id)
{
TEntity element = _dbContext.Set<TEntity>().Find(id);
_dbContext.Set<TEntity>().Remove(element);
}
}
}
When the above Remove method is called it makes two database call
One for getting the entity.
Second for deleting it.
I have found the query like the below one which executes with single SQL query
when the entity type(Employee or Project or Skill) is known
public void Remove(int id)
{
Employee employee = new Employee { EmployeeId = id };
_dbContext.Entry(employee).State = EntityState.Deleted;
}
can anyone please suggest me how to delete an entity without fetching it using a generic repository pattern similar to the above example.
Using raw SQL
Entity Framework doesn't allow you to delete an object that you haven't loaded (or attached). This also extends to conditional deletes (e.g. deleting all users named John) as it requires you to load the users before deleting them.
You can get around this by executing raw SQL. It's not ideal as you tend to use EF so you don't have to write SQL, but the lack of a decent delete behavior (without loading) makes this an acceptable solution.
Something along the lines of:
using (var context = new FooContext())
{
var command = "DELETE * FROM dbo.Foos WHERE Id = 1";
context
.Database
.ExecuteSqlCommand(command);
}
Where relevant, don't forget about SQL injection protection. However, it's usually a non-issue for simple deletes as the FK is usually a GUID or int, which doesn't expose you to injection attacks.
Making it generic
The example you posted works as well, but you're probably not using it because it can't easily be made generic-friendly.
What I tend to do in all my EF projects is to have an (abstract) base class for all my entities, something along the lines of:
public class BaseEntity
{
public int Id { get; set; }
public DateTime CreatedOn { get; set; }
public string CreatedBy { get; set; }
public DateTime? UpdatedOn { get; set; }
public string UpdatedBy { get; set; }
}
An interface would also work, I just prefer a base class here.
The audit fields are not part of this answer but they do showcase the benefits of having a base class.
When all your entities inherit from the same base class, you can put a generic type constraint on your repositories which ensures that the generic type has an Id property:
public class IRepositoy<TEntity> : IRepository<TEntity> where TEntity : BaseEntity
At which point you can generically implement your proposed solution:
public void Remove(TEntity obj)
{
dbContext.Entry(obj).State = EntityState.Deleted;
}
You can also specify a parameterless constructor type constraint:
where TEntity : BaseEntity, new()
which enables you to instantiate your generic type as well:
public void Remove(int id)
{
TEntity obj = new TEntity() { Id = id };
dbContext.Entry(obj).State = EntityState.Deleted;
}
Note
There is a generic raw SQL solution as well, but I've omitted it as it is more complex because it requires you to retrieve the table name based on the entity type.
The raw SQL variant is only valuable in cases where you want to execute conditional deletes (e.g. removing all entities whose id is an even number).
However, since most conditional deletes are entity-specific, this means that you generally don't need to make them generic, which makes the raw SQL approach more viable as you only have to implement it in a specific repository and not the generic one.
You still have to fetch it. Entity Framework caches your dbSets so it's usually pretty quick. Use the same context like so:
public virtual void Delete(object id)
{
TEntity entityToDelete = dbSet.Find(id);
Delete(entityToDelete);
}
public virtual void Delete(TEntity entityToDelete)
{
if (context.Entry(entityToDelete).State == EntityState.Detached)
{
dbSet.Attach(entityToDelete);
}
dbSet.Remove(entityToDelete);
}
Where dbSet =
context.Set<TEntity>();
The current limitation of Entity Framework is, in order to update or delete an entity you have to first retrieve it into memory. However there are few alternatives to delete a specific record.
You can try ExecuteSqlCommandto delete a specific record
_dbContext.Database.ExecuteSqlCommand("Delete Employee where EmployeeId = {0}", id );
or try using EntityFramework.Extended Library to delete a specific record
_dbContext.Settings.Where(s=> s.EmployeeId == id).Delete();

Trouble getting Entity in DB via primary key

I am building a relatively simple webapp, but have run into a bit of a problem. After having searched low and high, I can't seem to find anyone with similar issues.
So the situation:
I have an entity:
public class Entity
{
[Key]
public int EntityId { get; set;}
public string EntityName { get; set; }
public virtual ICollection<OtherEntity> OtherEntities { get; set; }
}
Reason for the virtual ICollection<OtherEntity> is a many to many relationship between the two.
My DbContext:
public class WebAppDB : IdentityDbContext<ApplicationUser>
{
public DbSet<Entity> Entities{ get; set; }
public WebAppDB () : base("DefaultConnection")
{
}
public static WebAppDB Create()
{
return new WebAppDB();
}
}
}
The default connection goes to an Amazon RDS SQL Server Express.
Around this I have created a repository:
public interface IEntityRepository
{
IQueryable<Entity> AlEntitiss { get; }
IQueryable<Entity> AllEntitissIncluding(params Expression<Func<Entity, object>>[] includeProperties);
Entity FindEntity(int id);
void InsertOrUpdateEntity(Entity entity);
void DeleteEntity(int id);
void Save();
}
public class EntityRepository : IEntityRepository
{
// handle to the database through the O.R.M. system.
private WebAppDB context = new WebAppDB();
public IQueryable<Entity> AllCEntitys
{
get { return context.Entitiss; }
}
public IQueryable<Entity> AllClassesIncluding(params Expression<Func<Entity, object>>[] includeProperties)
{
IQueryable<Entity> query = context.Entitiss;
foreach (var includeProperty in includeProperties)
{
query = query.Include(includeProperty);
}
return query;
}
public Entity FindEntity(int id)
{
return context.Entitiss.Find(id);
}
public void InsertOrUpdateEntity(Entity Entity)
{
if (Entity.EntityId == 0)
{
context.Entitiss.Add(Entity);
}
else
{
context.Entry(Entity).State = EntityState.Modified;
}
}
public void DeleteEntity(int id)
{
Entity Entity = FindEntity(id);
context.Entitys.Remove(Entity);
}
public void Save()
{
context.SaveChanges();
}
}
Now, the problem lies in the fact that I can get a list of the entities I have in the database and load them just fine into Selectlists or similar structures.
I can also get specific Entities based on other properties than the primary key.
But I can't get a single entity from the database using the primary key as my entry point. I have tried using DbSet.Entities.SingleOrDefault(), .Single(), .Find()
I have also tried to retrieve it using
DbSet.Entities.ToList().Where(x => x.EntityId == id)
I have moved from 2 data contexts down to 1, I have checked that I am referencing the same version of the EF in all projects in the solution (have a separate project for the entities).
After having read This, I fiddled with the Lazy loading, but no effect.
So I am running out of ideas and places to look.
If you need more information I will provide it to the best of my ability.
Thank you for reading and helping.
Update1:
I have tried moving to a local database with no luck, and it seems what I earlier described with loading lists of Entities working was exaggerated. They too don't load consistently when called.
Update 2:
Having used the SQL profiler to determine that not all calls from the controllers where executed on the database, I tried transplanting the entities to a fresh MVC project. Unfortunately the problem persists and I am out of ideas as this point.
Update 3:
After some more investigation and some help from Gert Arnold it has turned out that I misdiagnosed the initial problem. Due to poor coding practices it was not 1 central problem, but several separate problems all exhibiting similar characteristics that led me to the wrong conclusion that the EF was at fault. I am sorry to have wasted anyones time with this.
public Class FindEntity(int id)
{
//Want to find a specific student
return context.Entitys.Find(id);
}
This one seems a bit weird to me, what's the Class? I think it should be Student. Anyway, check out the code sample below:
public Entity FindEntity(int id)
{
return context.Entities.FirstOrDefault(e => e.EntityId == id); // note that it will return null if not found.
}

Entity Framework and adding POCOs without adding child objects

So perhaps I'm addressing this problem the wrong way, but I wanted to get the opinion from you fine people on StackOverflow about how to more correctly do this.
I've got a program that has to retrieve information from a repository around an Entity Framework 6.0 code-first context, do some work on the information contained and then it adds a new record to the database.
Anyway, here's the simplified look at the class I'm retrieving from EF through the repository:
public class Product
{
public int Id { get;set; }
public virtual ProductCategory Category { get;set; }
public string Name { get;set; }
}
I then build a ProcessedProduct with the following definition and pass in the previously retrieved Product as the BaseProduct:
public class ProcessedProduct
{
public int Id { get;set; }
public virtual Product BaseProduct { get;set; }
}
I use a repository layer that I saw on an EF lesson on Pluralsight and have purposed here. I've added all the relevant bits below:
public class MyContext : BaseContext<MyContext>, IMyContext
{
//Lots of IDbSets for each context
public void SetModified(object entity)
{
Entry(entity).State = EntityState.Modified;
}
public void SetAdd(object entity)
{
Entry(entity).State = EntityState.Added;
}
}
public class MyRepository : IMyRepository
{
private readonly IMyContext _context;
public MyRepository(IUnitOfWork uow)
{
_context = uow.Context as IMyContext;
}
public ProcessedProduct FindProcessedProduct(int id)
{
return _context.ProcessedProducts.Find(id);
}
public ProductCategory FindCategory(int id)
{
return _context.Categories.Find(id);
}
public int AddProcessedProductWithoutProduct(ProcessedProduct newRecord)
{
newRecord.Product = null;
Save();
return newRecord.Id;
}
public int UpdateProcessedProductWithProductButWithoutChildProperties(int processedProductId, int productId)
{
var processedProduct = FindProcessedProduct(processedProductId);
processedProduct.BaseProduct = FindProduct(productId);
processedProduct.BaseProduct.Category = null;
_context.SetModified(product);
Save();
return processedProduct.Id;
}
public int UpdateProductChildren(int processedProductId, int categoryId)
{
var processedProduct = FindProcessedProduct(processedProductId);
var category = FindCategory(categoryId);
processedProduct.BaseProduct.Category = category;
_context.SetModified(product);
Save();
return processedProduct.Id;
}
}
And finally, here's the portion that pulls it all together:
try
{
//Create the processed product without the product instance
var processedProductId = repo.AddProcessedProductWithoutProduct(finishedProduct);
//Now, update this processed product record with the product. This way, we don't create a
//duplicate product.
processedProductId = repo.UpdateProcessedProductWithProductButWithoutChildProperties(processedProductId, product.Id);
//Finally, update the category
processedProductId = repo.UpdateProductChildren(processedProductId, product.Category.Id);
//Done!
}
When I attempt to insert this ProcessedProduct into EF, it correctly creates the ProcessedProduct record, but it also creates a new Product and new Category row. I've tried manually changing the change tracking for each object so ProcessedProduct would be 'added' and the others would be either 'modified' or 'unchanged', but I would get foreign key reference exceptions thrown by Entity Framework.
My "fix" was to simply break this up into a number of different calls:
I create the new ProcessedProduct record, but I assign the Product value to null.
I query for that ProcessedProduct record with the Id, query for the appropriate Product with its Id and assign that Product to the newly retrieved ProcessedProduct record. However, I have to null out the Category property or else this will add a new duplicate Category record. I save and the ProcessedProduct record is modified.
Finally, I query the ProcessedProduct once more as well as the ProductCategory and then assign that ProductCategory to the Category property of the ProcessedProduct.BaseProduct. I can save once more and now I've created all the records I need without making any of the duplicates.
However, this approach seems quite convoluted since all I originally wanted to do is save the new parent record and simply not create duplicate child records. Is there a better way to go about doing this that I'm missing? Thanks!
Edit: And I guess the larger question is say I have a complex object with a whole bunch of these child complex objects. What's the easiest way to create a new parent without having to go through the entire graph of child objects to update the parent with them one layer at a time?
I highly recommend not setting Product & Category as navigation properties when editing. As you saw when you add the graph of processed product (with a product & category attached) to the EF context, it's marking everything in the graph as added and does inserts on everything.
The pattern I always recommend (and Nikolai also suggested in his comment, so up-vote his comment like I did :)) is to include the FK IDs in your entity and set those values, not the navigations. e.g.
newRecord.ProductId=theProductIdValue.
I've had many people cry "but foreign keys? ewwww! They will make my classes so dirty and impure!" but after they see how much easier it is to code things without tangling with the navigations in these scenarios, they have come back to say "okay, it was worth it!"
BTW if you are talking about my EF in the Enterprise course, I have a whole module about dealing with this problem...it's called something bout graphs in disconnected scenarios. :)

How to manually set entity primary key in Entity Framework code first database?

Well, I have the following model structure: I have one class - DatabaseEntity which is basically
public class DatabaseEntity
{
public int Id { get; set; }
}
so each entity like product, category etc will inherit DatabaseEntity and have Id property. Also I have typical EntityFramework repository class with InsertOrUpdate method:
private readonly DbContext _database;
public void InsertOrUpdate<TObject>(TObject entity) where TObject : DatabaseEntity
{
if(entity.Id == default(int))
{
// New entity
DbSet<TObject>().Add(entity);
}
else
{
// Existing entity
_database.Entry(entity).State = EntityState.Modified;
}
_database.SaveChanges();
}
Then I download from eBay via eBay api list of categoies I have to add to database. Basically category is:
public class EbayCategory : DatabaseEntity
{
// It has Id since it inherits DatabaseEntity
public string Name { get; set; }
// ... some other properties
}
But, the problem is, when I download those categories I download and their Id properties, which, of course, already have values. And when I try to save them to database like:
public void UpdateCategories(IEnumerable<EbayCategory> newCategories)
{
foreach (var newCategory in newCategories)
{
_repository.InsertOrUpdate(newCategory);
}
}
I face some issues... First of all, entity.Id != default(int) because it has value, so repository tries to update this entity, instead of adding, but it is not in the database or context so it throws the following exception:
System.Data.Entity.Infrastructure.DbUpdateConcurencyException
"Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries."
... because it thinks that someone else deleted entity which I am trying to update. How can I save this InsertOrUpdate logic, since a lot of projects are based on it, and be able to add items (EbayCategories) with primary key (Id) to database and then update/delete them like other entities without discarding EbayCategory.Id value?
To allow you to manually generate Ids you need a class that has a manually generated ID - so it cannot inherit from DatabaseEntity
public class EbayCategory
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
public string Name { get; set; }
// ... some other properties
}
Now you will need a different InsertOrUpdate to handle entities that have manually generated keys:
public void InsertOrUpdate(EbayCategory entity)
{
if(Find(entity.ID == null)
{
// New entity
DbSet<EbayCategory>().Add(entity);
}
else
{
// Existing entity
_database.Entry(entity).State = EntityState.Modified;
}
_database.SaveChanges();
}
Colin's answer above quite correctly shows how to achieve this setting using data annotations.
But in the presented problem the entity is a subclass so you can't add the annotation without changing the entity class.
There is an alternative configuration method: Fluent Configuration. Here's my example using an EntityTypeConfiguration class:
public class LookupSchoolsConfiguration : EntityTypeConfiguration<LookupSchools>
{
public LookupSchoolsConfiguration()
{
Property(l => l.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
}
}
You can also add configuration directly to the modelBuilder as per this post: https://stackoverflow.com/a/4999894/486028

Categories