-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Addressing "Temporal Table" feature feedback #3353
Comments
@smitpatel So as to not derail dotnet/efcore#25365 , here is my reply to your comment:
Got it. I think the hard part for some people, like me, is there is somewhat opaque terms like "set operation", "navigation expansion", "manual joins", "consistency of the result graph", etc. that the audience is presumed to be familiar with. I don't know if there is a glossary of terms, but I wasn't trying to derail this question on purpose. I just didn't know what this issue was fully about. In particular, I didn't grok what "consistency of the result graph" meant until you brought up referential integrity and it clicked for me that you need to be able to round trip these objects with change tracking. (I'm actually not 100% sure I fully grok it, but I do understand that a temporal dimension makes typical third normal form expressed via navigation properties insufficient.) Related, I don't know things like "Is Include operator part of 'navigation expansion'?" Separately, I personally don't run preview builds of EFCore - I find that installing the latest preview SDK causes unpredictable local environment dependencies that might hamper my abilities to do my day job on stable environments. Here is my rough shot at a small slang glossary: Set Operation: Also known as DbSet Operation. Operations that are only supported on a DbSet rather than any IQueryable type. These Operations are: Navigation Expansion: Also known as query expression syntax for navigating relationships. Unclear whether this also refers to eager loading via Navigation Propagation: ? - I am not not sure how to articulate this, even though I think I understand what is meant by it. Temporal Operation: Operations that are only supported on a DbSet that has entity model metadata for temporal table support. These Operations are: Manual Joins: Also known as query expression syntax for join operators. Manual joins are explicit instructions for how to construct a join, and do not look at entity model metadata to determine things like key relationships. Put another way, manual joins are not computed via an algorithm, they are simply de facto join operations with direct translations to SQL. Consistency of the Result Graph: Also known as referential integrity rules. Consistency refers to the object graph not violating the object dependency rules specified in the entity model metadata, e.g. required dependent, optional dependent, etc. I don't know if the above gives you angina or is a relief and improvement - but my intentions are for the best. As a brief example, I used Google Books search and searched Entity Framework Core In Action for the phrase "navigation expansion" and it appears 0 times. So, I don't think I am just gesticulating when I say it's an esoteric term that could use a clear meaning. I also think clearer meanings produce better test cases because it will be clearer what the SUT is. In other words, even though the LINQ problem space is infinite, the meaning of these words cannot be. |
It is easy to blur common terms in particular context if it is looked outside of context or applying very specific constraint set over it. While my years of working for EF Core, none of those terms have caused confusion for users hence we use those terms frequently. But alas, there is always first time. So I will describe them here. Set operation - a mathematical set operation which refers to Union/Intersection/Except (Concat which is also Union but without removing duplicates). I have mentioned this in my earlier response too. We never called any DbSet operation set operation, we always refer to DbSet as DbSet even though API is called Navigation expansion - Navigations don't exist in database. Any navigation property configured in EF Core model needs to be transformed into an equivalent join in database. EF Core does this particular task for users. The big reason for using ORM is having an easy way to write queries using navigations rather than writing multiple joins as a user. While the part expansion refers to expanding the navigation into a join, anything relating to navigation expansion refers to using any kind of navigation which is in EF Core model in LINQ query (which starts with DbSet query root). There is no navigation propagation. There is propagation of facets from one entity to another entity which is traversed through a navigation property. So if you do AsOf on Customers and use Manual joins - Since EF Core expands navigations into join, when there are no navigation properties or they cannot be used, user is required to what EF Core does internally for navigation, write a join between tables themselves. Since user is initiating the join we call it manual join (rather than implicit join through navigation). Consistency of result graph - When multiple entities are connected by referential integrity constraint then they contains foreign keys. The foreign key dictate the association. But when you pick a record from previous time in temporal table the associated record may not be present in current time. Though at that point in time the record existed without violating constraint, we can find associated entity in same point in time. This is what we do wrt navigation expansion and AsOf operation. Going beyond that which is over a duration, requires that we understand more than just FK configured as a single record with given primary key could have multiple records for different dates. So in order to connect we also need to look at the dates. Which becomes even harder since SqlServer stores start and end date for each record so we are not matching exact value but time periods. This is just creating results part, consuming results would involve similar complexity in terms of understanding it. So this become pit of failure especially if assumptions and computations made along the way are not what user expected. So we resolved it by blocking the scenario and letting user write joins the way they want and generate results however they want. The full user control mode. I understand the difficulty in using preview build and it is not cup of tea for everyone. We would like feedback from customers about feature and hence we release preview. I believe that this feedback in not being useful as it doesn't incorporate the usage of feature in direct way, it doesn't point out any obvious gaps in the feature. Everything you asked query wise in other thread is possible to do with the feature we have shipped. If you cannot use preview builds then I suggest you wait till final release and once you have used feature, provide us feedback. Currently it is just spending time for both of us for this which works and very easy to see when you have running code. |
Thanks for this work. It is very useful. Certain migrations seem to cause the exception:
Reproduce:
modelBuilder.Entity<Student>().ToTable(tb => tb.IsTemporal());
Output is the aforementioned exception. A temporal table with a named history table does not cause the exception, and these steps do not cause the exception in preview 6 but do in preview 7. I am also able to cause the exception under other circumstances (in both preview 6 and 7), but it's not yet clear to me what the exact conditions need to be to trigger it. Any advice? Is this a known bug? |
@benjaminsaljooghi Thanks, I will investigate. We were not aware of this bug. |
@benjaminsaljooghi filed an issue: dotnet/efcore#25511, fix is on the way. Workaround is what you have already figured out - explicitly provide history table name. Thanks for the early report! |
Thanks @maumar that fixed the anonymous history tables and also fixed other issues I was getting pertaining to the same exception. I am now able to generate migrations and it works perfectly, but I am getting build warnings caused by my migrations here: .OldAnnotation("SqlServer:TemporalHistoryTableSchema", null) where public virtual AlterOperationBuilder<TOperation> OldAnnotation(string name, object value) However, because the schema argument is
Therefore, should the |
@benjaminsaljooghi apologies for a late reply. This issue is tracked by dotnet/efcore#18950. As a workaround we will temporarily opt out of NRT (tracked by dotnet/efcore#25624) |
@maumar I am facing a similar issue to @benjaminsaljooghi above however it is not a warning but a runtime exception. Utilising // OnModelCreating
modelBuilder.Entity<Post>().ToTable(tb => tb.IsTemporal(ttb =>
{
ttb.UseHistoryTable("Posts_History");
ttb.HasPeriodStart(temporalPeriodStartName); // "_PeriodStart"
ttb.HasPeriodEnd(temporalPeriodEndName); // "_PeriodEnd"
})); // Migration: Up
migrationBuilder.AlterTable(
name: "Posts")
.Annotation("SqlServer:IsTemporal", true)
.Annotation("SqlServer:TemporalHistoryTableName", "Posts_History")
.Annotation("SqlServer:TemporalPeriodEndColumnName", "_PeriodEnd")
.Annotation("SqlServer:TemporalPeriodStartColumnName", "_PeriodStart");
// Migration: Down
migrationBuilder.AlterTable(
name: "Posts")
.OldAnnotation("SqlServer:IsTemporal", true)
.OldAnnotation("SqlServer:TemporalHistoryTableName", "Posts_History")
.OldAnnotation("SqlServer:TemporalHistoryTableSchema", null) // <--- Causing issues
.OldAnnotation("SqlServer:TemporalPeriodEndColumnName", "_PeriodEnd")
.OldAnnotation("SqlServer:TemporalPeriodStartColumnName", "_PeriodStart"); Issues are faced only when attempting to revert the migration whereby the line .OldAnnotation("SqlServer:TemporalHistoryTableSchema", null) causes the following exception
Replacing .OldAnnotation("SqlServer:TemporalHistoryTableSchema", null) with .OldAnnotation("SqlServer:TemporalHistoryTableSchema", string.Empty) resolves the issue and allows the revert to complete successfully however I'm not sure as to the validity of the statement and am pondering whether the line should even exist at all given the annotation is not assigned in the Up migration. |
Closing. Please file any new issues on https://github.com/dotnet/efcore |
I have
in my OnModelCreating() and SysStartTime and SysEndTime columns already exist in the table, but when I execute add-migration, migrations to add these columns are generated. |
Placeholder for Temporal Tables feedback from customers as well as EF Team addressing the feedback / improvements.
The text was updated successfully, but these errors were encountered: