RowVersion implementation on Entity Framework for PostgreSQL - postgresql

I am using Entity Framework 6 with PostgreSQL.
I have an entity in which I want to prevent concurrency issues, following this documentation I added a RowVersion property with [Timestamp] attribute, however after saving changes to the entity the column RowVersion value stays the same in the database.
[Timestamp]
public byte[] RowVersion { get; set; }
Am I missing something or is there another way to handle it in PostgreSQL?

Just an updated answer for EF Core in case anyone else wanders here.
The Npgsql framework has built-in support for this using the hidden system column xmin that the OP is using in his entity as a NotMapped property.
As referenced here, you can set the xmin column as a concurrency token within EF by calling the UseXminAsConcurrencyToken method on your entity within its OnModelCreating method via Fluent API (a Data Annotation is not available at this time as far as I'm aware).
For anyone already using Fluent API configurations, it's as simple as this:
public class AwesomeEntityConfiguration : IEntityTypeConfiguration<AwesomeEntity>
{
public void Configure(EntityTypeBuilder<AwesomeEntity> builder)
{
builder.UseXminAsConcurrencyToken();
}
}

/// <summary>
/// Meant to validate concurrency en database update
/// This column is updates itself in database and only works in postgresql
/// </summary>
[ConcurrencyCheck]
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
//[NotMapped]
public string xmin { get; set; }
Had to add [NotMapped] attribute just for the column not to be added in the migration, commented it after database-update.

Related

To add navigation property without foreign key in EF Core, DB-first migration with .NET Core Web API

I am working with an existing system and updating it to .NET Core, Web API and EF Core.
The existing system has 2 tables:
Parent table: Id, name, etc..
Child table: Id, ParentId, name, etc..
Though ParentId exists in the child table, there is no foreign key reference, but I want to be able to use include when I query the parent. I have asked not to add FK as part of deleting they are putting -ve values to parentId column. This way they can bring it back and a legacy system was built that way.
Now, in db-first migration how can I specify a navigation property without fk so my EF Core to act relational; or at least return them together. Adding nullable foreign key is not an option as it will break the system when -ve values are added.
I do have suggested for full cleanup of DB and getting rid of -ve values but that involves lots of testing and no deliverable. So long story short how to add navigation property without foreign key in database first migration ?
I tried adding collection and virtual entry in the model, but after migration it got overwritten. I have added this by using HasMany on modelbuilder as per this document - https://learn.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-simple-key%2Csimple-key
But scaffolding is overriding my navigation property
I found out the answer for this.
In EF core 3.x the dbcontext created by DBFrist scaffolding is all partial classes.
So I did the following:
1. new partial class for context class - here i added the relationship of navigation property using OnModelCreatingPartial() method. Example below
public partial class dbContext : DbContext
{
partial void OnModelCreatingPartial(ModelBuilder builder)
{
builder.Entity<Packcomponent>()
.HasOne(p => p.Pack)
.WithMany(b => b.PackComponent)
.HasForeignKey(p => p.PackId);
}
}
extended the partial class in a new file and added navigation property there.
public partial class Packcomponent
{
public Pack Pack { get; set; }
}
public partial class Pack
{
public List PackComponent { get; set; }
}
This way upon scaffolding it did not overwrite custom navigation properties and I also could use this properties to do EF operations like .Include() and to save related entities as well. It is pretty awesome!!

Entity Framework - Database generated identity is not populated after save if it is not the key of the entity

I have a model like
public class MyEntity
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Required]
public int Id { get; set; } // Id
[Required]
[Key]
public System.Guid GUID { get; set; }
}
The GUID property is the PK by design, but I have a db generated Id property that I use within my code to determine if the object is a new object that hasn't been saved yet.
When I save this object with Entity Framework, the Id property does not get back populated as normally happens for database generated properties (although usually these are keys). I have to query the DB for the object and grab the ID manually. It seems EF only back populates Key properties on SaveChanges.
Is there any way to get EF to automatically populate the Id property here? Setting it as the Key is not an option, I have dozens of tables that are FK'd to the GUID property and for good reason.
EDIT: I have discovered that the package https://entityframework-extensions.net/ is handling my save changes. If I use the standard EF savechanges it works, but not with the extensions version.
Disclaimer: I'm the owner of Entity Framework Extensions
It was indeed an issue in our library. This scenario was not yet supported for EF6.
However, starting from the v4.0.50, it should now work as expected.

Table per concrete type in EF Core

I have built the following model of hierarchy for DB:
public abstract class ApplicationUser : IdentityUser
{ }
public class FirstUser : ApplicationUser
{}
public class SecondUser : ApplicationUser
It is noticeable abstract Application class inherits from ASP.NET Core Identity's not abstarct class IdentityUser.
So my purpose is building different tables for UserFirst and UserSecond only, not for IdentityUser and ApplicationUser.
I tried to configure model the following:
builder.Ignore<IdentityUser>();
builder.Entity<FirstUser>().ToTable("FirstUsers");
builder.Entity<SecondUser>().ToTable("SecondUsers");
However it throws exception: Invalid column name 'Discriminator'
What can I do?
Table per Concrete Type (TPC) or Table per Type (TPT) aren't currently supported in EntityFrameework Core 1.0. Only Table per Hierarchy (TPH) is supported.
TPC and TPT are on the high priority list and may come in EntityFramewor Core 1.1 or 1.2, see the EntityFramework Core Roadmap.
Backlog Features
...
High priority features
...
Modelling
More flexible property mapping, such as constructor parameters, get/set methods, property bags, etc.
Visualizing a model to see a graphical representation of the code-based model.
Simple type conversions such as string => xml.
Spatial data types such as SQL Server's geography & geometry.
Many-to-many relationships without join entity. You can already model a many-to-many relationship with a join entity.
Alternate inheritance mapping patterns for relational databases, such as table per type (TPT) and table per concrete type TPC.
As for your question:
You can't do anything about it. If you absoloutely need this feature, you have to fall back to EntityFramework 6.x, but then you can't target .NET Core and have to target .NET Framework 4.x.
It should be noted here, that Microsoft do not feels (or recommends) to use EntityFramework Core 1.0 yet in production environment, if you require the features used from EF6. It will take several versions (at least 2 minor releases) until EntityFramework Core will get anyway close featurewise to EF6.
So if TPC is absolute requirement, go back to EF6.
Technical stuff aside, performance wise it's prefered to use TPH for mapping inheritance to your database as it avoids unnecessary joins during queries. When you use TPT/TPC every query invovling it will have to perform joins and joins are less performant.
So unless you have to map to a legacy DB designed in that way, you should fall back to TPH.
Table-per-concrete-type (TPC) mapping is now available in EFC 7.0.0 nightly builds.
https://github.com/dotnet/efcore/issues/3170
https://github.com/dotnet/efcore/issues/3170#issuecomment-1124607226
https://learn.microsoft.com/en-gb/ef/core/what-is-new/ef-core-7.0/plan#table-per-concrete-type-tpc-mapping
What you need to try it out:
.NET SDK 7.0.100-preview.4
https://dotnet.microsoft.com/en-us/download/dotnet/7.0
Visual Studio 2022 Preview 17.3
https://visualstudio.microsoft.com/vs/preview/
NuGet
Microsoft.EntityFrameworkCore 7.0.0-preview.4.22229.2
Code example:
ApplicationDbContext:
using Microsoft.EntityFrameworkCore;
namespace WebApplicationNet7.Data
{
public class ApplicationDbContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<RssBlog> RssBlogs { get; set; }
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>().UseTpcMappingStrategy();
modelBuilder.Entity<RssBlog>().UseTpcMappingStrategy();
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
public class RssBlog : Blog
{
public string RssUrl { get; set; }
}
}
Migration will look like this:
Note that RssBlog is missing .Annotation("SqlServer:Identity", "1, 1").
You will probably get a warning that looks like this:
Microsoft.EntityFrameworkCore.Model.Validation[20609]
The property 'BlogId' on entity type 'Blog' is configured with a
database-generated default, however the entity type is mapped to the
database using table per concrete class strategy. Make sure that the
generated values are unique across all the tables, duplicated values
could result in errors or data corruption.
I could not get it to work with either setting
modelBuilder.Entity<RssBlog>().Property(u => u.BlogId).UseIdentityColumn(); or using annotation [DatabaseGenerated(DatabaseGeneratedOption.Identity)].

EF Code First One-To-One with Join Table

I am trying to configure my model to an existing database, and am running into a problem. The previous developer modeled a one-to-one relationship using a join table. If I have the following classes and database structure below, how can I map this using code first?
public class Title {
public Property Property { get; set; }
}
public class Property {
public Title TitleInsurance { get; set; }
}
tbTitle
-TitleID = PK
tbPropertyToTitle
-TitleID - FK to tbTitle.TitleID
-PropertID - FK to tbProperty.PropertyID
tbProperty
-PropertyID = PK
Code in VB.Net here, but should be easy to translate. Mark primary keys with the Key data attribute. Entity Framework will automatically look for properties named Class + ID, i.e. tbTitleID to assign as primary keys, but since that isn't applicable here, we need the Key attribute.
Overridable properties denote Navigation Properties. In C#, this should be equivalent to Virtual properties. When this navigation property is accessed, Entity Framework will automatically look for valid foreign key relations, and populate the appropriate data.
For a one-to-one relationship, Entity Framework expects that your two tables share the same primary key, as shown by TitleID here.
Public Class tbTitle
<Key()>
Public Property TitleID As Integer
...
Public Overridable Property Property As tbProperty
End Class
Public Class tbProperty
<Key()>
Public Property TitleID As Integer
...
Public Overridable Property Title As tbTitle
End Class
Looking through the fluent API, I don't see any way to map one to one relations through a join table. You might be able to fake it by setting it up as a many to many but then you would need a bit of extra code to ensure that your relation collections only ever have one item in them.

Why is entity framework not annotating some non nullable columns as required?

I am using EF 4.1 with database first.
Example table:
CREATE TABLE dbo.Foo(
[ID] [int] IDENTITY(1,1) NOT NULL,
Created datetime not null default(getdate()),
Title varchar(80) not null
PRIMARY KEY CLUSTERED ([ID] ASC)
)
EF correctly loads the model with all 3 columns as nullable = false.
Output from code generation item "ADO.NET DbContext Generator":
public partial class Foo
{
public int ID { get; set; }
public System.DateTime Created { get; set; }
public string Title { get; set; }
}
In MVC3 I generate the FooController via the db context and foo model. When I bring up /Foo/Create and hit "Create" on the blank form it shows a validation error on "Created" field but not on "Title".
If I enter only a "created" date I get an exception:
Validation failed for one or more entities. See 'EntityValidationErrors'
property for more details
The exception is "The Title field is required".
I'm not sure why it works fine for one column but not the other. My first fix was to simply add the annotation, however the class code is auto generated by EF.
The only fix that seems to work is to use a partial metadata class: ASP.NET MVC3 - Data Annotations with EF Database First (ObjectConext, DbContext)
I can add the [Required] tag as desired however this should be unnecessary. Is this a bug in EF or am I just missing something?
This isn't a bug, EF simply doesn't add those attributes. As far as i know, the database-first approach (Entity classes generated by the designer) doesn't even perform the validation. The link you're refering to is a valid solution for your problem. The principle of buddy-classes which contain the actual metadata was introduced due to the fact, that you cannot add attributes to existing properties in a partial class.
The code-first approach has a built-in functionality to validate your annotations, see: Entity Framework 4.1 Validation. Another solution when using database-first would be to create a custom code-generator that applies those attributes T4 Templates and the Entity Framework.