EntityFramework-Plus icon indicating copy to clipboard operation
EntityFramework-Plus copied to clipboard

Auditing Where extension method throws exception

Open Nate129 opened this issue 5 years ago • 4 comments

Description

I am unable retrieve audit entries for a generic type using the Where<T>() extension method.

Exception

System.Exception
Unhandled exception. System.Exception: Oops! The number of argument for the key specified doesn't match with the number of key members. Please report the issue including the stack trace to our support team: [email protected]
   at Z.EntityFramework.Plus.AuditExtensions.Where[TAuditEntry,T](DbSet`1 set, Object[] keyValues)
   at Z.EntityFramework.Plus.AuditExtensions.Where[T](DbSet`1 set, Object[] keyValues)

Fiddle or Project

https://dotnetfiddle.net/bEDZTU

Further technical details

  • EF version: EF Core 5
  • EF Plus version: 5.1.2
  • Database Provider: Sqlite (also happens using Sql Server in fiddle)

Nate129 avatar Nov 23 '20 20:11 Nate129

I also experienced the issue on EF Core 3.1.10 (latest before 5) and equivalent EF Plus version (3.1.2).

Nate129 avatar Nov 23 '20 20:11 Nate129

Thank you for the project @NWhittle ,

We will look at it.

Best Regards,

Jon


Performance Libraries context.BulkInsert(list, options => options.BatchSize = 1000); Entity Framework ExtensionsEntity Framework ClassicBulk OperationsDapper Plus

Runtime Evaluation Eval.Execute("x + y", new {x = 1, y = 2}); // return 3 C# Eval FunctionSQL Eval Function

JonathanMagnan avatar Nov 23 '20 21:11 JonathanMagnan

Hello @NWhittle ,

Sorry for the long waiting,

Unfortunately retrieving the audit with the Where method doesn't work as you want.

See: https://entityframework-plus.net/ef-core-audit-retrieve-audit-entries-for-specific-item

You can either pass an item or the key:

using (var ctx = new TestContext())
{
    ctx.AuditEntries.Where(item);
    ctx.AuditEntries.Where<Entity_Basic>(item.ID);
    ctx.AuditEntries.Where<Entity_Basic>(101);
}

If you wish to return all items for a specific type, here is an online example: https://dotnetfiddle.net/bZdD0q

var customers = context.AuditEntries.Where(x => x.State == AuditEntryState.EntityAdded && x.EntityTypeName == "Customer").ToList();

(I also added the AutoSavePreAction which was missed from your example)

Let me know if that helped you.

Best Regards,

Jon

JonathanMagnan avatar Nov 26 '20 21:11 JonathanMagnan

Hi @JonathanMagnan,

Thank you for your reply. My goal (as you correctly determined) was to retrieve all entries for a type without retrieving any of that type's entities from the database first, so the first link you provided doesn't seem relevant for my use case.

I initially wrote a query like the one you suggested to accomplish my goal, but then I went to use the generic type argument I had available, i.e:

var customers = context.AuditEntries.Where(x => x.State == AuditEntryState.EntityAdded && x.EntityTypeName == typeof(T).Name).ToList();

I concluded that this must be the incorrect way to query the entries by type because EF Plus sets the x.EntityTypeName internally when creating the entries and as such would, for the purpose of api design consistency, resolve generic types internally as well since the strategy for storing the name of a given type is 'hidden away' from the user. If EF Plus did not resolve them internally, then users would then be left to guess by testing to figure out which strategy EF Plus used to store the name of the entity class, i.e. typeof(T).Name, typeof(T).FullName, or typeof(T).FullyQualifiedName, etc.

I believe this is the primary reason I expected the generic Where<T>() extension method to support the type of query I was trying to use it for- I was expecting to find some method to allow EF Plus to resolve my generic type argument for me since it did so when creating the entry internally.

Since I seem to have found an alternative which allows me to continue using the auditing feature (although my code won't be as concise), I consider myself unblocked and will continue using EF Plus for my project.

Perhaps I could provide some feedback, given my thought process when learning the EF Plus api:

  • If the Where<T> is working as intended, then it would seem that a more specific exception would help fortify the api against misuse- the one I received seemed to be a fallback exception, which made me think I had encountered a bug
  • It would seem, given the previous point as the final strategy for improving the product, that the documentation could use an update to more accurately reflect the intended usages of the Where<T> extension method- I interpreted it to be a convenience method to interact with entries for a generic type, which it turns out is a broader scope than it actually seems to be
  • Going further, perhaps the api could be updated to also provide a method or methods or update the Where<T> method to resolve the type names for a generic types for the user- it does so internally when creating the entries so it would seem like the same would be expected when querying the entries. It seems to me that it's not a good experience for the user to have to guess which strategy EF Plus used internally to generate the type name for the entry

I will leave the issue open in case my feedback should be represented as an open issue. If this is not appropriate I can close it since I am unblocked.

Thanks,

Nathan

Nate129 avatar Dec 01 '20 21:12 Nate129