Entity Framework Code First Migration for Computed Column - asp.net-mvc-4

I am trying to add a computed column HasAnyCheck that returns true if any or both Check1 and Check2 is true.
My model:
public bool Check1 { get; set; }
public bool Check2 { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public bool HasAnyCheck { get; private set; }
My migration:
public override void Up()
{
Sql("ALTER TABLE [MyTable] ADD [HasAnyCheck] AS ([Check1] = 1 OR [Check2] = 1)");
}
public override void Down()
{
DropColumn("dbo.MyTable", "HasAnyCheck");
}
When I run Update-Database I get the error Incorrect syntax near '='.

I suspect the issue is your computed_column_expression does not explicitly return a value:
ALTER TABLE [MyTable] ADD [HasAnyCheck] AS CAST((CASE WHEN [Check1]=1 OR [Check2]=1 THEN 1 ELSE 0 END) AS BIT)
in your case you could potentially also get away with bitwise OR:
ALTER TABLE [MyTable] ADD [HasAnyCheck] AS ([Check1]|[Check2])

Related

EF Code First ApplicationUser required DateTime not added

I have a problem registering new users with my new ASP.NET Core Application (Code First).
When registering i'm using an `ApplicationUser` inheriting from `IdentityUser`.
public class ApplicationUser : IdentityUser
{
[Required]
[DefaultValue(5)]
public int ViewerRange { get; set; }
[DefaultValue(false)]
[Required]
public bool IsTACAccepted { get; set; }
public DateTime? TACAccepted { get; set; }
[Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public DateTime Created { get; set; }
[Required]
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime Modified { get; set; }
public string Role { get; set; }
public ApplicationUser()
{
Modified = DateTime.Now;
Created = DateTime.Now;
}
}
HereĀ“s the part of Register.cshtml.cs
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl ??= Url.Content("~/");
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (ModelState.IsValid)
{
var user = new ApplicationUser
{
UserName = Input.Email,
Email = Input.Email,
Role = Input.Role,
Created = DateTime.Now,
Modified = DateTime.Now,
IsTACAccepted = false,
ViewerRange = 5
};
var result = await _userManager.CreateAsync(user, Input.Password);
//[...]
When registering, the CreateAsync Method fails with the following error:
InvalidOperationException: The value for property 'ApplicationUser.Modified' cannot be set to null because its type is 'System.DateTime' which is not a nullable type.
I can't understand why this is failing.
Can someone explain in detail please?
Kind regards
The reason for the error is that [DatabaseGenerated(DatabaseGeneratedOption.Computed)] says its value is generated by the database, so any assigned value should be ignored. The error shows this isn't the case though.
This isn't the only oddity in the code. [DatabaseGenerated(DatabaseGeneratedOption.Identity)] on a DateTime makes no sense. IDENTITY is used to autoincrement numeric fields. This has no meaning for a DateTime column.
f you want to specify the values yourself, remove the DatabaseGenerated attributes and use them as normal fields. You can avoid the explicit assignment by specifying a default property value, eg
public DateTime Created { get; set; } = DateTime.Now;
public DateTime Modified { get; set; } = DateTime.Now;
It's also possible to configure the database to generate those values. This is described in the docs, in the Generated Values article. Adding Created and Modified columns is described in the Date/time generation section.
A default value constraint for the Created column can be specified with HasDefaultValueSql :
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.Created)
.HasDefaultValueSql("getdate()");
}
The Modified timestamp needs a trigger though, which can't be specified in a DbContext's model. This must be created in the database, either directly :
CREATE TRIGGER [dbo].[Blogs_UPDATE] ON [dbo].[Blogs]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF ((SELECT TRIGGER_NESTLEVEL()) > 1) RETURN;
DECLARE #Id INT
SELECT #Id = INSERTED.BlogId
FROM INSERTED
UPDATE dbo.Blogs
SET LastUpdated = GETDATE()
WHERE BlogId = #Id
END
Or through a raw SQL migration that executes the same script :
migrationBuilder.Sql(
#"
EXEC ('CREATE TRIGGER [dbo].[Blogs_UPDATE] ON [dbo].[Blogs]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
IF ((SELECT TRIGGER_NESTLEVEL()) > 1) RETURN;
DECLARE #Id INT
SELECT #Id = INSERTED.BlogId
FROM INSERTED
UPDATE dbo.Blogs
SET LastUpdated = GETDATE()
WHERE BlogId = #Id
END')");
public DateTime? Created { get; set; }
public DateTime? Modified { get; set; }
Use this, your model needs to be told that there can be null values inside your database, otherwise it will assume there aren't.
UPDATE
**I did not actually carefully noticed your error. Now I will update my answer:-**
I see you did not use this property in your controller. so initially this property nullable. for that you found this issue. first of all, use this property to ignore nullable.
Try like this:-
public DateTime TACAccepted { get; set; } = DateTime.Now;
You can try this because your property it's null. You set this property like the above code for ignoring the nullable. or you remove this property from your model if it's don't need. I think it's will resolve your issue.
Also, make sure that column is declared as a DateTime in your SQL Database.

How can I map my sorting to SQL correctly?

I have the following class:
public class ReturnDto
{
[Column("PARC_NUM")]
public int ParcelNumber { get; set; }
~[Column("CUSTOM_TAXE")] or [Column("AUTOMATIC_TAXE")]~
public decimal Taxe { get; set; }
}
I'm working in this Api using Dapper/Dommel and that class is supposed to be filled with the values from the data base. The problems is that it doesn't work for the second property (the "Taxe" one) because, as follows, the Query have two possible columns to take the value from:
...
ag.PARC_NUM AS ,
case when pp.IDT_MODALID = 3 then ag.CUSTOM_TAXE else ag.AUTOMATIC_TAXE end AS Taxe,
...
I tried setting the column name as Taxe (because that's how I name it, after all), but it just doesn't get mapped correctly. Actually, it just throws an exception poiting that such thing doesn't exist.
I am missing some standard setting or it just can't be done that way?
Try assign one of the valid column name
case when pp.IDT_MODALID = 3
then ag.CUSTOM_TAXE
else ag.AUTOMATIC_TAXE
end AS AUTOMATIC_TAXE ,
or add a field in the class
public class ReturnDto
{
[Column("PARC_NUM")]
public int ParcelNumber { get; set; }
~[Column("CUSTOM_TAXE")] or [Column("AUTOMATIC_TAXE")]~
public decimal Taxe { get; set; }
[Column("TAXE")]
public decimal Taxe { get; set; }
}

Error while inserting in a table containing identity column System.Data.Entity.Infrastructure.DbUpdateException

In my ASP.Net MVC 4 project I'm trying to insert data into a table which has identity an auto-increment column (ACTIVITYID), which is the Primary Key.
Table Class
public partial class ACTIVITY
{
public decimal ACTIVITYID { get; set; }
public Nullable<decimal> CALLTICKETNUMBER { get; set; }
public string ACTION { get; set; }
public Nullable<long> STATUSIDATTHETIMEOFACTION { get; set; }
public short RECORDFORDISPLAY { get; set; }
public Nullable<System.DateTime> ACTIVITYDATE { get; set; }
public string USER_ { get; set; }
public virtual CALLTICKET CALLTICKET { get; set; }
}
Upon calling the following method generates exception
public static void AddActivity(long ticketNumber, string action, string userId, int? previousStatusId = null)
{
var newActivity = new ACTIVITY
{
ACTION = action,
ACTIVITYDATE = System.DateTime.Now,
CALLTICKETNUMBER = ticketNumber,
STATUSIDATTHETIMEOFACTION = previousStatusId,
USER_ = userId,
};
dbOraContext.ACTIVITies.Add(newActivity);
dbOraContext.SaveChanges();
}
While viewing ACTIVITies.Add(newActivity) ACTIVITYID is inserting with value 0.
On tracing the inner exception following exception is displayed:
{"ORA-00001: unique constraint (ATM_CRM.PK_ACTIVITY) violated"}
Also, an exception of type 'System.Data.Entity.Infrastructure.DbUpdateException' occurred.
Earlier I have worked with MS SQL Server, and never encountered such a problem. Auto-increment column should automatically get its value.
Note that I'm working on Oracle DB.

Retrieve Big data using EF

I have two tables "Kelime"
public class Kelime
{
public int ID { get; set; }
public string Word { get; set; }
public DateTime Date { get; set; }
}
and "Anlam"
public class Anlam
{
public int ID { get; set; }
public string Meaning { get; set; }
public DateTime Date { get; set; }
public int Kelimesi_ID { get; set; }
[ForeignKey("Kelimesi_ID")]
public virtual Kelime kelime { get; set; }
}
Both tables contains more than 80k datas. I don't think they are very big but I am having problem on this query:
Repository<Kelime> _rk = new Repository<Kelime>();
Repository<Anlam> _ra = new Repository<Anlam>();
IEnumerable<int> kelimeIdler = _ra.All().Select(s => s.Kelimesi_ID).Distinct();
int _kelimecik= _rk.Find(w => !kelimeIdler.Contains(w.ID)).ID;
or Kelime _kelimecim = _rk.All().Where(w => !kelimeIdler.Contains(w.ID)).FirstOrDefault();
I am trying to take the "Kelime", "Kelime List" or its "id" it doesn't matter which are not in my "Anlam" table. There is a timeout when it comes to "contains" part. I tried to write non clustered index but it doesn't accept subquery. What should I do to achieve what I want? Thank you very much.
private static DataContext _context;
public static DataContext ContextOlustur()
{
if (_context == null)
{
_context = new DataContext();
}
return _context;
}
Adding this pattern to my data context class solved my problem. Because my queries used two different context that's why it was getting problem to connect database and got time out. This pattern prevents creating another context.

One-to-Many relation to existed table in EF6: The ALTER TABLE statement conflicted with the FOREIGN KEY constraint

So now I'm trying to use Code first approach with a couple of existed tables.
So before now I have an existed table with model:
[Table("Existed1")]
public class TimeSerieEntity
{
[Key]
[Column(Order = 0)]
[StringLength(3)]
public string TsId { get; set; }
[Key]
[Column(Order = 1, TypeName = "date")]
public DateTime Date { get; set; }
public double Value { get; set; }
}
And this entity illustrate time series element. So Now I need to add new Entity which has One-to-Many relation with this data. So I add class
public class TSRootEntity
{
[Key]
[StringLength(3)]
public string Code { get; set; }
public virtual ICollection<TimeSerieEntity> Values { get; set; }
}
and change TimeSerieEntity to this one:
[Table("Existed1")]
public class TimeSerieEntity
{
[Key, ForeignKey("TSMD")]
[Column(Order = 0)]
[StringLength(3)]
public string TsId { get; set; }
[Key]
[Column(Order = 1, TypeName = "date")]
public DateTime Date { get; set; }
public double Value { get; set; }
public virtual TSRootEntity TSMD { get; set; }
}
and add the following mapping:
`modelBuilder.Entity<TSRootEntity>()
.HasMany(c => c.Values)
.WithRequired(ts => ts.TSMD)
.WillCascadeOnDelete(false);
But when I trying to run migration it fails with error:
{"'PK_dbo.Existed1' is not a constraint.\r\nCould not drop constraint. See previous errors."}
Please, help me to fix this.
For some reason it's try to use PK_dbo.Existed1 but there is no such Constraint in DB, but there is PK_Existed1 Why EF add this dbo prefix?
UPD2:
I solved 1st problem just with renaming PK constraint. But now I have different exception:
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_dbo.Existed1_dbo.TSRootEntity_TsId". The conflict occurred in database "testdb", table "dbo.TSRootEntity", column 'Code'.
Ok. Found the problem. So last error caused because of Existed1 already have data, and TSRootEntity is empty. So it's try to map actuall foreign keys, to non existed primary keys. And that's make it fails.
So to solve that, we need prefill TSRootEntity as well. The question is - what is the most elegant way to do that?