Using Entity Framework's Fluent API, I can successfully insert a new row in the user's table using this code:
modelBuilder.Entity<User>().ToTable("Users");
modelBuilder.Entity<User>().HasKey(x => x.UserId);
However, I also want to set the CreatedBy field based on the Guid assigned to the UserId. The following code does not work:
modelBuilder.Entity<User>().Property(x => x.CreatedBy)
.HasDefaultValueSql("SCOPE_IDENTITY()");
I would appreciate any suggestions. Thanks.
This can be done using the .HasComputedColumnSql.
Example:
modelBuilder.Entity<Contact>()
.Propery(p => p.LastModified)
.HasComputedColumnSql("GetUtcDate()");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<SalesOrderHeader>()
.Property(e => e.SalesOrderNumber)
.HasComputedColumnSql("isnull(N'SO'+CONVERT([nvarchar](23),[SalesOrderID]),N'*** ERROR ***')");
}
Here is the link you can refer to:
HasComputedColumnSql Method
hope this helps,
HK
Related
How to user Map method in Entity Framework Core 6. After upgrading to Entity Framework Core 6 the Map() method no longer works. Is there something similar I can use to Map the columns to a table?
Example of my code below.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
foreach (var relationship in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
{
relationship.DeleteBehavior = DeleteBehavior.Restrict;
}
modelBuilder.Entity<RoleGroup>()
.HasMany(c => c.Roles).WithMany(i => i.RoleGroups).Map(t => t.MapLeftKey("RoleGroupId")
.MapRightKey("RoleId")
.ToTable("RoleGroupRole"));
}
Most examples for EF Core have a RoleGroupRole entity defined, but they do support using a Dictionary<string, object> for a shadow entity placeholder for basic joining tables:
modelBuilder.Entity<RoleGroup>
.HasMany(u => u.Roles)
.WithMany(g => g.RoleGroups)
.UsingEntity<Dictionary<string, object>>(
right => right
.HasOne<Role>()
.WithMany(),
left => left
.HasOne<RoleGroup>()
.WithMany(),
join => join
.ToTable("RoleGroupRoles"));
The gotcha with this configuration is that the expressions for the two sides goes "Right" then "Left", it's easy to get them backwards. :)
I'm trying to upgrade the OwnedTypes sample to EF Core 3.0 Preview 8 but when I run the project it can't create the database.
When Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade.EnsureCreated() is called the following exception is thrown:
Microsoft.Data.SqlClient.SqlException: 'Cascading foreign key 'FK_OrderDetails_DetailedOrders_OrderId' cannot be created where the referencing column 'OrderDetails.OrderId' is an identity column.
Could not create constraint or index. See previous errors.'
What previous errors? 🤔
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
#region OwnsOneNested
modelBuilder.Entity<DetailedOrder>().OwnsOne(p => p.OrderDetails, od =>
{
od.OwnsOne(c => c.BillingAddress);
od.OwnsOne(c => c.ShippingAddress);
});
#endregion
#region OwnsOneTable
modelBuilder.Entity<DetailedOrder>().OwnsOne(p => p.OrderDetails, od =>
{
od.OwnsOne(c => c.BillingAddress);
od.OwnsOne(c => c.ShippingAddress, sa =>
{
sa.Ignore(p => p.IgnoreMe);
});
od.ToTable("OrderDetails");
});
#endregion
}
Full project
I assume there is something in the 3.0 breaking changes list I need to follow?
You can remove od.ToTable("OrderDetails"); to map OrderDetails to the same table as DetailedOrder
You can add od.Property("OrderId").ValueGeneratedNever(); to disable marking the OrderId column as identity
I'm manually moving from .NET Framework to .NET Core and working on the EF and DTOs.
I'm not enjoying this - I have read indexes are not supported via annotation and as such, am currently mixing fluent api and annotations which is a code smell. However, it appears as if I must proceed with this combination.
My question is if I can achieve this only with fluent api. My table has both a primary key and a unique constraints.
My object looks like
class Person
{
public int Id {get;set;}
public string UniqueToken {get;set;}
}
However, I am unable to add the following
modelBuilder.Entity<Person>()
.HasKey(a => a.Id)
.HasIndex(a => a.UniqueToken).IsUnique(); //this is what I would like to add but I can't.
I've attempted something which feels like a hacky work around
modelBuilder.Entity<Person>()
.HasKey(a => a.Id);
modelBuilder.Entity<Person>()
.HasIndex(a => a.UniqueToken).IsUnique();
Again, adding this entry twice seems a little bleugh… Fluent appears to want to simply chain the methods.
I have read on this, but I'm getting very lost. Is it possible to add both the primary key and unique constraint ?
Better you separate your entity configurations from OnModelCreating method with IEntityTypeConfiguration interface as follows:
public class PersonConfiguration : IEntityTypeConfiguration<Person>
{
public void Configure(EntityTypeBuilder<Person> builder)
{
builder.HasKey(a => a.Id);
builder.HasIndex(a => a.UniqueToken).IsUnique();
}
}
Now you can add configuration for all of your Db entities like PersonConfiguration and register all of them at once as follows:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(typeof(PersonConfiguration).Assembly);
}
This will give you more separation of concern and readability!
I have understood the following code
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>()
.MapToStoredProcedures(p => p.Insert(sp => sp.HasName("sp_InsertStudent").Parameter(pm => pm.StudentName, "name").Result(rs => rs.Student_ID, "Student_ID"))
.Update(sp => sp.HasName("sp_UpdateStudent").Parameter(pm => pm.StudentName, "name"))
.Delete(sp => sp.HasName("sp_DeleteStudent").Parameter(pm => pm.Student_ID, "Id"))
);
}
But still I have few questions
1. If I have button called calculate and want to call some other procedure apart from CRUD. How can I call that SP?
2. How can I pass list of model/entity (collection) to procedure as parameter? or any other solution.
If you have access to your DbContext class where you want to call the stored procedure, you can simply do:
var studentStuff = dbContext.Database.SqlQuery<Student>
("dbo.DoSomethingWithStudent #studentID",
new SqlParameter("#studentID", studentID));
You can't pass a complex model directly to a SQL stored procedure.
If your procedure returns no results it would be:
dbContext.Database.ExecuteSqlCommand("EXEC dbo.DoSomethingWithStudent #studentID",
new SqlParameter("#studentID", studentID));
I have created a new clean asp.net 5 project (rc1-final), I just need to change default ef identity table name.
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
protected override void OnModelCreating(ModelBuilder builder)
{
// On event model creating
base.OnModelCreating(builder);
// Define table name
builder.Entity<IdentityUser>().ToTable("BackEnd_AspNetUsers").Property(p => p.Id).HasColumnName("UserId");
builder.Entity<ApplicationUser>().ToTable("BackEnd_AspNetUsers").Property(p => p.Id).HasColumnName("UserId");
builder.Entity<IdentityUserRole<string>>().ToTable("BackEnd_AspNetUserRoles");
builder.Entity<IdentityUserLogin<string>>().ToTable("BackEnd_AspNetUserLogins");
builder.Entity<IdentityUserClaim<string>>().ToTable("BackEnd_AspNetUserClaims");
builder.Entity<IdentityRole>().ToTable("BackEnd_AspNetRoles");
}
}
I get following error
InvalidOperationException: Cannot use table 'BackEnd_AspNetUsers' in schema '' for entity 'ApplicationUser' since it is being used for another entity.
These lines here show you are trying to setup mappings for both the base identity classes and your application's inherited version of these classes;
builder.Entity<IdentityUser>().ToTable("BackEnd_AspNetUsers").Property(p => p.Id).HasColumnName("UserId");
builder.Entity<ApplicationUser>().ToTable("BackEnd_AspNetUsers").Property(p => p.Id).HasColumnName("UserId");
You don't need both, you should only have the inherited one specified - ApplicationUser.
In your case you should use ForSqlServerToTable("newtablename")
builder.Entity<IdentityUser>().ForSqlServerToTable("BackEnd_AspNetUsers").Property(p => p.Id).HasColumnName("UserId");
builder.Entity<ApplicationUser>().ForSqlServerToTable("BackEnd_AspNetUsers").Property(p => p.Id).HasColumnName("UserId");