What's the best way to force EF to return all

2019-09-18 03:00发布

问题:

I have a view where one of the joined columns is nullable but is often the only distinguishing item between two rows. I see that EF built a primary key out of all the non-nullable items in the view. I've noticed that when I pull from the view, this nullable column does not always get returned correctly, and I read that it has to do with the way it maps to the key, and will return the same row if it sees the key already exists.

Ideally the best solution would be to make my column not-nullable, but I can't do that without causing larger problems.

The other idea was to use ROW_NUMBER() to make a primary key. I am unsure whether that may cause similar issues (if the context isn't refreshed between calls, would it go solely off that or it is smart enough to realize that the queries are different?) I also worry about performance of needing an ORDER BY for the function and how that would affect dynamic ordering of the rows.

What is the best way to ensure all my rows are returned exactly as they appear through the SQL query with the least hit to performance?

Thank you..

Example:

view: A int, B int, C int?

SQL Results:
1, 2, null
1, 3, 10
1, 3, 11

EF will return something like :

1, 2, null
1, 3, 10
1, 3, 10

I need to get that 11, too.

回答1:

This happens due to identity map pattern. By default EF keep track of already loaded entities (identified by the entity key) - if the result set contains repeating entity key EF thinks that it is the same entity as the one already loaded and it doesn't create a new entity instance for those repeating records - instead it uses the instance created for the first record with that key. This is necessary for change tracking and for ability to save changes back to the database.

In your case you most probably don't want to save changes back to database because these records don't give you necessary information to be able to do that. So load records without change tracking and it should skip identity map pattern and generate new entity instance for every record in the result set:

context.YourEntitySet.MergeOption = MergeOption.NoTracking; 
// Now execute your query