Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DbSet<T>.Find by alternate key or predicate #12469

Closed
BalassaMarton opened this issue Jun 26, 2018 · 7 comments
Closed

DbSet<T>.Find by alternate key or predicate #12469

BalassaMarton opened this issue Jun 26, 2018 · 7 comments

Comments

@BalassaMarton
Copy link

It would be nice to have a version of DbSet<T>.Find that works with an alternate key or predicate.

  // Find by alternate key
  string barcode = "123456789";
  var product = db.Products.Find(p => p.Barcode, barcode);
  // Find by predicate
  var keyboards = db.Products.Find(p => p.Category == "Keyboard");

The proposed signatures:

  public TEntity Find<TKey>(Expression<Func<TEntity, TKey>> keySelector, TKey value);
  public TEntity Find(Expression<Func<TEntity, bool>> predicate);

Functionally, this can be achieved with extension methods, by first searching the local set, but it would perform better if there was an identity map for alt. keys and Find would search using that.

@ajcvickers
Copy link
Member

@BalassaMarton This has been discussed several times in the past--for example, see #10303. Find has two advantages over executing a query:

  • It is a simple API that takes a key value and nothing more
  • It looks in the DbContext cache first and only does a query to the database if needed

Any time we look at expanding the Find API we always come to the conclusion that it would be better to just write a query. That is, it doesn't retain the first advantage of Find.

As for the second advantage, #1948 covers how this could be added to normal LINQ queries. Taking these two things together, the conclusion has been that we should implement #1948 instead.

@BalassaMarton
Copy link
Author

@ajcvickers This is something that I've come across in an actual ETL project. Take this very simple example where we have a flat input with ProjectCode, ProjectName, ProjectStatus; and an EF Core target with Project entity that has long primary key and Code alternate key.
Let me first show you what doesn't work:

foreach (var sproj in source) {
    var proj = db.Projects.FirstOrDefault(p => p.Code == sproj.ProjectCode) ?? new Project { Code = sproj.ProjectCode };
    proj.Status = sproj.ProjectStatus;
    db.Projects.Update(proj);
}

When we hit the same project code a second time, FirstOrDefault will still return null since we haven't called SaveChanges yet. We could call SaveChanges after every update, but that would severely violate our nice unit of work pattern or whatever. The proposed overload to Find is precisely what you wrote: "It looks in the DbContext cache first and only does a query to the database if needed". That is what I need, look at the local set first, just like the original Find.

@ajcvickers
Copy link
Member

@BalassaMarton We discussed this in triage and came to the conclusion that once #7391 (as referenced from #10303) is implemented, then it will be possible to easily to efficient lookup by key or alternate key in the state manager, which will allow different types of Find to be implemented as extension methods.

@BalassaMarton
Copy link
Author

Sounds great, thank you.

@Neme12
Copy link

Neme12 commented Aug 13, 2019

@ajcvickers The advantage of Find over queries is that it ignores global query filters. If we want to use queries to find a specific entity by ID, we need call IgnoreQueryFilters() on the query.

@BalassaMarton
Copy link
Author

It does? That would be a huge issue in a multi-tenant environment.

@Neme12
Copy link

Neme12 commented Aug 13, 2019

Sorry I was wrong, I thought they were only used for queries.

@ajcvickers ajcvickers reopened this Oct 16, 2022
@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Oct 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants